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
随机推荐
- C++-POJ3349-Snowflake Snow Snowflakes[STL][set][hash未写]
错误AC解法,sort+set判重,为考虑异构! 比较坑的一点是读入时scanf一定要一次读6个数,不然会TLE #include <set> #include <map> # ...
- codeforces Codeforces Round #597 (Div. 2) B. Restricted RPS 暴力模拟
#include <bits/stdc++.h> using namespace std; typedef long long ll; ]; ]; int main() { int t; ...
- 1059 Prime Factors (25分)
1059 Prime Factors (25分) 1. 题目 2. 思路 先求解出int范围内的所有素数,把输入x分别对素数表中素数取余,判断是否为0,如果为0继续除该素数知道余数不是0,遍历到sqr ...
- day11 ss命令 查看网络端口使用情况及对应pid centos7
[root@oldboyedu ~]# ss -lntup Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port udp UNC ...
- CSS 盒子模型属性
盒子模型(Flexible Box) 属性 属性 说明 CSS box-align 指定如何对齐一个框的子元素 3 box-direction 指定在哪个方向,显示一个框的子元素 3 box-flex ...
- Docker - 查看容器进程在宿主机的 PID
概述 查看 docker 进程, 在容器外的 pid 背景 docker 中运行的进程, 本质上是运行在 host 上的 这些进程, 在 host 上, 也可以有自己的 pid 如果某种情况下, 连不 ...
- jmeter-下载安装使用
jmeter介绍 jmeter是什么? jmeter是apache组织开发的,开源的,纯java的压力测试工具. jmeter可以用来测什么? ——|__静态资源(发送给客户端的文件) |__动态资源 ...
- [USACO13JAN]Cow Lineup
Description Luogu3069 USACO Solution 由于两个点之间最多可以有\(k+1\)种牛,而牛的种数是单调的.所以可以用尺取法(区间伸缩法),每次右移右端点后,让左端点不断 ...
- SpringBoot集成mybatis以及自动化测试代码实现
Mybatis和logback的应用配置 1.在module的pom.xml文件中,加载springboot和swagger.lombok.fastjson.mysql.mybatis包 2.在res ...
- Bugku - Misc图穷匕见 - Writeup
Bugku - Misc图穷匕见 - Writeup 原文链接:http://www.cnblogs.com/WangAoBo/p/6950547.html 题目 给了一个jpg图片,下载图片 分析 ...