这里测试使用的是协程的quasar框架。
代码使用CountDownLatch对线程进行控制,分别检测其创建和运行时间。
时间测试:
设想以下的场景,使用15个线程来调用某加了同步锁的方法,每次这个方法的执行时间在25ms左右,那线程和协程都需要多少时间完成方法调用:
线程:
创建时间:2-3ms
运行时间:375ms
协程:
创建时间:150ms
运行时间:375ms
可以发现协程的创建要比线程的创建花费更多的时间。
cpu占用测试:
另外从cup的占用角度来分析两者的区别,因为375ms太短,所以将线程数改为150来测试:
上图的左侧是协程运行的情况,右侧是线程运行的情况,总的来说,协程运行的cup占用峰值要比线程小,但持续时间比线程长。所以其实对一些长时间执行的任务,协程的运行开销应该比线程小一些。
去掉同步锁的情况:
另外协程对线程的优势应该上下文切换频繁的场景,所以不用锁的情况可能协程的运行效率更高,将同步锁去掉继续测试:
发现在线程数在150以上的情况下,协程的运行时间要比线程短,且随着线程数的增长,这种差距会增大。
总结:
所以总的来说,平时的场景时不太需要协程的,只有在线程常驻内存来处理长任务时,或是在需要大量线程来并发的时候,协程的效率会比线程高。对于一些短的任务,并发较少的情况,线程反而更具优势。
测试代码:
线程:
/**
* @Auther: muyu
* @Date: 2018-10-09-16:33
*/
import java.util.concurrent.CountDownLatch;
class service{
public void sleeps(CountDownLatch endGate, CountDownLatch startGate){
try {
startGate.await();
Thread.sleep(25);
System.out.println(Thread.currentThread().getName());
endGate.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class threadDemo implements Runnable{
service ser = new service();
CountDownLatch startGate;
CountDownLatch endGate;
public threadDemo(service ser,CountDownLatch endGate,CountDownLatch startGate){
this.ser = ser;
this.startGate = startGate;
this.endGate = endGate;
}
public void run() {
ser.sleeps(endGate,startGate);
}
}
public class test4 {
public static void main(String[] args){
service ser = new service();
threadDemo[] t = new threadDemo[150];
CountDownLatch startGate = new CountDownLatch(1);
CountDownLatch endGate = new CountDownLatch(150);
for(int i=0;i<t.length;i++){
t[i] = new threadDemo(ser,endGate,startGate);
Thread t1 = new Thread(t[i]);
t1.start();
}
long startTime = System.currentTimeMillis();
startGate.countDown();
try {
endGate.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("用时: " + (endTime - startTime) + "ms");
}
}
协程:
import co.paralleluniverse.fibers.Fiber;
import co.paralleluniverse.fibers.SuspendExecution;
import co.paralleluniverse.strands.Strand;
import co.paralleluniverse.strands.SuspendableRunnable;
import java.util.concurrent.CountDownLatch;
/**
* @Auther: muyu
* @Date: 2018-10-11-16:52
*/
class service2 {
public void doSleep(CountDownLatch startGate, CountDownLatch endGate) throws SuspendExecution {
try {
startGate.await();
Strand.sleep(25);
System.out.println(Thread.currentThread().getName());
endGate.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class threadDemo2 implements SuspendableRunnable {
service2 ser2 = new service2();
CountDownLatch startGate;
CountDownLatch endGate;
public threadDemo2(service2 ser2,CountDownLatch startGate,CountDownLatch endGate){
this.ser2 = ser2;
this.startGate = startGate;
this.endGate = endGate;
}
@Override
public void run() throws SuspendExecution, InterruptedException {
ser2.doSleep(startGate,endGate);
}
}
public class xieChengTest {
public static void main(String[] args) throws InterruptedException, SuspendExecution {
service2 ser = new service2();
threadDemo2[] fiber = new threadDemo2[150];
CountDownLatch startGate = new CountDownLatch(1);
CountDownLatch endGate = new CountDownLatch(150);
for(int i=0;i<fiber.length;i++){
fiber[i] = new threadDemo2(ser,startGate,endGate);
Fiber f = new Fiber(fiber[i]);
f.start();
}
long startTime = System.currentTimeMillis();
startGate.countDown();
try {
endGate.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("用时: " + (endTime - startTime) + "ms");
}
}