這裏測試使用的是協程的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");
}
}