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
随机推荐
- Razor视图中的@:和语法
Razor视图中的@:和语法 原创changuncle 最后发布于2016-12-07 17:43:50 阅读数 4456 收藏 展开 在MVC项目中新建视图的时候默认支持ASPX引擎和Razor引 ...
- python skimage库的安装
skimage库需要依赖 numpy+mkl 和scipy 1.打开运行,输入cmd回车,输入python回车,查看python版本
- 配置yum仓库:yum install 软件
1.一个重要模板: 进入/etc/yum.repos.d文件夹,新建一个xiaoxu.repo文件,其中xiaoxu可以根据需要来取名. [模板] vim xiaoxu.repo [rhel] ...
- qt5.9.0 msvc2015优雅的崩溃:dumpfile
交给客户的软件奔溃了怎么办? 我们不能再客户电脑上安装vs,也不想傻傻的用log来猜测出错的地方. 利用Dbghelp可以解决这一问题. 首先是vs生成release版本的时候需要同时生成pdb文件, ...
- 题解 P6013 【压岁钱】
月赛\(\text{Div2T1}\),窝唯一一道\(\text{AC}\)的题(我太菜啦!) \(\text{solution:}\) 根据题面,显然三个操作对应三种情况,我们发现每次这三种操作均不 ...
- Lenet 神经网络-实现篇(2)
Lenet 神经网络在 Mnist 数据集上的实现,主要分为三个部分:前向传播过程(mnist_lenet5_forward.py).反向传播过程(mnist_lenet5_backword.py). ...
- Bugku-CTF分析篇-手机热点(有一天皓宝宝没了流量只好手机来共享,顺便又从手机发了点小秘密到电脑,你能找到它吗?)
手机热点 httppan.baidu.coms1cwwdVC 有一天皓宝宝没了流量只好手机来共享,顺便又从手机发了点小秘密到电脑,你能找到它吗? 题目来源:第七季极客大挑战
- CTF_论剑场 头像
首先打开链接发现这个链接是一个头像 然后下载这个头像 通过hxd分析一下 在编辑中查找 flag 然后发现flag是一个用base64 加密的一串文字 然后我们将这串文字 解密 然后再通过md5 32 ...
- 1.3 eclipse快捷键
来源:http://blog.csdn.net/dashuxiaoai/article/details/8737928 另:Eclipse快捷键 10个最有用的快捷键 http://www.cnbl ...
- 有源汇有上下界最大流 (ZQU1591)
题意:现在的网络有一个源点s和汇点t,求出一个流使得源点的总流出量等于汇点的总流入量,其他的点满足流量守恒,而且每条边的流量满足上界和下界限制. 思路:要满足每一个点的流量守恒,我们可以尝试像无源汇上 ...