java 协程
协程是比线程更轻量级的程序处理单元,也可以说是运行在线程上的线程,由自己控制
1.适用于被阻塞的,且需要大量并发的场景。
2.不适用于,大量计算的多线程,遇到此种情况,更好实用线程去解决。
虽然Java的线程的API封装的很好,使用起来非常的方便,但是使用起来也得小心。首先线程需要耗费资源,所以单个的机器上创建上万个线程很困难,其次线程之间的切换也需要耗费CPU,在线程非常多的情况下导致很多CPU资源耗费在线程切换上,通过提高线程数来提高系统的性能有时候适得其反。你可以看到现在一些优秀的框架如Netty都不会创建很多的线程,默认2倍的CPU core的线程数就已经应付的很好了,比如node.js可以使用单一的进程/线程应付高并发。
纤程使用的资源更少,它主要保存栈信息,所以一个系统中可以创建上万的纤程Fiber,而实际的纤程调度器只需要几个Java线程即可。
我们看一个性能的比较,直观的感受一下Quasar带来的吞吐率的提高。
下面这个例子中方法m1调用m2,m2调用m3,但是m2会暂停1秒钟,用来模拟实际产品中的阻塞,m3执行了一个简单的计算。
通过线程和纤程两种方式我们看看系统的吞吐率(throughput)和延迟(latency)。
package com.zhou.quasar.quasar; import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;
import java.util.stream.Collectors;
import java.util.stream.Stream; import co.paralleluniverse.fibers.Fiber;
import co.paralleluniverse.fibers.SuspendExecution;
import co.paralleluniverse.fibers.Suspendable;
import co.paralleluniverse.strands.Strand;
import co.paralleluniverse.strands.SuspendableRunnable; public class Helloworld {
@Suspendable
static void m1() throws InterruptedException, SuspendExecution {
String m = "m1";
// System.out.println("m1 begin");
m = m2();
// System.out.println("m1 end");
// System.out.println(m);
} static String m2() throws SuspendExecution, InterruptedException {
String m = m3();
Strand.sleep(1000);
return m;
} @Suspendable
static String m3() {
List l = Stream.of(1, 2, 3).filter(i -> i % 2 == 0).collect(Collectors.toList());
return l.toString();
} public static void main(String[] args) throws ExecutionException, InterruptedException {
int count = 10000;
testFiber(count);
testThreadpool(count);
} static void testThreadpool(int count) throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(count);
ExecutorService es = Executors.newFixedThreadPool(200);
LongAdder latency = new LongAdder();
LongAdder counter = new LongAdder();
long t = System.currentTimeMillis();
WrappyInteger sum=new WrappyInteger(0);
for (int i = 0; i < count; i++) {
es.submit(() -> {
// Long long1=sum;
long start = System.currentTimeMillis();
try {
m1();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (SuspendExecution suspendExecution) {
suspendExecution.printStackTrace();
}
start = System.currentTimeMillis() - start;
latency.add(start);
counter.add(1);
sum.i++;
latch.countDown();
});
}
latch.await();
t = System.currentTimeMillis() - t;
long l = latency.longValue() / count;
System.out.println("thread pool took: " + t + ", latency: " + l + " ms------"+counter.longValue()+"sum ---"+sum.i);
es.shutdownNow();
} static void testFiber(int count) throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(count);
LongAdder latency = new LongAdder();
LongAdder counter = new LongAdder();
WrappyInteger sum=new WrappyInteger(0);
long t = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
new Fiber<Void>("Caller", new SuspendableRunnable() {
@Override
public void run() throws SuspendExecution, InterruptedException {
long start = System.currentTimeMillis();
m1();
start = System.currentTimeMillis() - start;
counter.add(1);
latency.add(start);
sum.i++;
latch.countDown();
}
}).start();
}
latch.await();
t = System.currentTimeMillis() - t;
long l = latency.longValue() / count;
System.out.println("fiber took: " + t + ", latency: " + l + " ms,------"+counter+"--sum"+sum.i);
} static class WrappyInteger{
public int i; public WrappyInteger(int i) {
this.i = i;
} }
}
运行这个程序(需要某种instrument, agent--启动时java代理,或者AOT--编译时已完成代理时工作,或者其它,在下面会介绍),输出结果为:
QUASAR WARNING: Quasar Java Agent isn't running. If you're using another instrumentation method you can ignore this message; otherwise, please refer to the Getting Started section in the Quasar documentation.
fiber took: , latency: ms,--------sum10000
thread pool took: , latency: ms------10000sum ---
1、Quasar Java Agent
Quasar java agent可以在运行时动态修改字节码,将下面一行加搭配java命令行中即可,注意把path-to-quasar-jar.jar替换成你实际的quasar java的地址。
另外一种是在编译时的时候完成instrumentation
<plugin>
<groupId>com.vlkan</groupId>
<artifactId>quasar-maven-plugin</artifactId>
<version>0.7.3</version>
<configuration>
<check>true</check>
<debug>true</debug>
<verbose>true</verbose>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>instrument</goal>
</goals>
</execution>
</executions>
</plugin>
3、在Web容器中
如果你使用web容器使用基于Quasar的库comsat等,比如Tomcat,则比较棘手。因为你不太像将Quasar java agent直接加到tomcat的启动脚本中,这样会instrument所有的应用,导致很多的警告。
Comsat提供了Tomcat和Jetty的解决方案。
Tomcat
对于tomcat,你可以把comsat-tomcat-loader-0.7.0-jdk8.jar或者comsat-tomcat-loader-0.7.0.jar加入到tomcat的common/lib或者lib中,然后在你的web应用META-INF/context.xml中加入:
|
1
|
<Loader loaderClass="co.paralleluniverse.comsat.tomcat.QuasarWebAppClassLoader" /> |
Jetty
如果使用Jetty,则把comsat-jetty-loader-0.7.0-jdk8.jar或者comsat-jetty-loader-0.7.0.jar加入到Jetty的lib中,然后在你的context.xml中加入<Set name="classLoader">:
|
1
2
3
4
5
6
7
8
9
10
11
|
<Configure id="ctx" class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="war">./build/wars/dep.war</Set> <!--use custom classloader in order to instrument classes by quasar--> <Set name="classLoader"> <New class="co.paralleluniverse.comsat.jetty.QuasarWebAppClassLoader"> <Arg> <Ref id="ctx"/> </Arg> </New> </Set></Configure> |
总之,通过实现一个定制的ClassLoader实现instrumentation。
java 协程的更多相关文章
- Java协程实践指南(一)
一. 协程产生的背景 说起协程,大多数人的第一印象可能就是GoLang,这也是Go语言非常吸引人的地方之一,它内建的并发支持.Go语言并发体系的理论是C.A.R Hoare在1978年提出的CSP(C ...
- Java协程编程之Loom项目尝鲜
前提 之前很长一段时间关注JDK协程库的开发进度,但是前一段时间比较忙很少去查看OpenJDK官网的内容.Java协程项目Loom(因为项目还在开发阶段,OpenJDK给出的官网https://ope ...
- JAVA协程 纤程 与Quasar 框架
ava使用的是系统级线程,也就是说,每次调用new Thread(....).run(),都会在系统层面建立一个新的线程,然鹅新建线程的开销是很大的(每个线程默认情况下会占用1MB的内存空间,当然你愿 ...
- java 协程框架quasar gradle配置
https://github.com/puniverse/quasar-gradle-template/blob/master/gradle/agent.gradle 1.将其中的"-jav ...
- java 协程框架kilim
http://phl.iteye.com/blog/2247112 http://chen-tao.github.io/2015/10/02/kilim-work-way/ 待丰富
- Java之协程(quasar)
一.前面我们简单的说了一下,Python中的协程原理.这里补充Java的协程实现过程.有需要可以查看python之协程. 二.Java协程,其实做Java这么久我也没有怎么听过Java协程的东西,但是 ...
- Java不支持协程?那是你不知道Quasar!
原创:微信公众号 码农参上,欢迎分享,转载请保留出处. 在编程语言的这个圈子里,各种语言之间的对比似乎就一直就没有停过,像什么古早时期的"PHP是世界上最好的语言"就不提了,最近我 ...
- 异步时代-java的协程路在何方
面试官:你知道协程吗? 你:订机票的那个吗,我常用. 面试官:行,你先回去吧,到时候电话联系 ........ 很尴尬,但是事实是,很大一部分的程序员不知道协程是啥玩意,更大一部分的程序员,项目中没用 ...
- 都2019年了,Java为什么还在坚持多线程不选择协程?
都2019年了,Java为什么还在坚持多线程不选择协程? - 知乎 https://www.zhihu.com/question/332042250/answer/734051666
随机推荐
- b 解题报告
本题已收录至2019/9/15 本周总结 题目 [问题描述] Hja有一棵\(n\)个点的树,树上每个点有点权,每条边有颜色.一条路径的权值是这条路径上所有点的点权和,一条合法的路径需要满足该路径上任 ...
- powerdesigner16.5改变数据模型字体大小
1. 点击 2. 选择 3. 选择完点击确定后: 4. 点击设为默认:再点ok
- 牛客竞赛第二场D Kth Minimum Clique 贪心+bitmap
Kth Minimum Clique 题意 给出n(n<100)个点的邻接表,和n个点的权值,求第k大的团(完全子图) 分析 n很小,并且好像没有什么算法和这个有关系,所以可以往暴力枚举的方向想 ...
- [Note]后缀自动机
后缀自动机 代码 #include <cstdio> #include <algorithm> #include <cstring> const int M = 1 ...
- Java传(1)
____________________________去告诉世界,我已经横空出世了! 你好丫,世界! public class HelloWorld{ public static void main ...
- Navicat图形更改表结构的时,设置外键时出现1452错误
原文地址:http://www.mamicode.com/info-detail-1296600.html 提示1452错误,如下图所示. 然后百度了一下,得到了一个靠谱的答案: 这是因为表设置了外键 ...
- android WebView缩放时卡顿问题
问题描述: WebView 在双指缩放页面时会卡顿 解决过程:有试过打开硬件加速android:hardwareAccelerated="true" 还是没用,纠结了一天,最后屏蔽 ...
- Flask 教程 第二十一章:用户通知
本文翻译自The Flask Mega-Tutorial Part XXI: User Notifications 这是Flask Mega-Tutorial系列的第二十一章,我将添加一个私有消息功能 ...
- 8.14-T2捕老鼠(cat)
题目大意 有 N 个仓库,排成了一排,编号为 1-N.假设在第 i 个仓库点燃艾条,烟雾就会充满该仓库,并向左右扩散Ai的距离,接着所有|i-j|<=Ai的仓库 j 的老鼠被消灭.最少需要多少支 ...
- SqlDataAdapter对象
https://blog.csdn.net/qq_39657909/article/details/80615465 一.特点介绍 1.表示用于填充 DataSet 和更新 SQL Server 数据 ...