• 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: 1382, latency: 1015 ms,------10000--sum10000
    thread pool took: 50184, latency: 1000 ms------10000sum ---9999

    1、Quasar Java Agent
    Quasar java agent可以在运行时动态修改字节码,将下面一行加搭配java命令行中即可,注意把path-to-quasar-jar.jar替换成你实际的quasar java的地址。

    -javaagent:path-to-quasar-jar.jar
    2、AOT(Ahead-of-Time)
    另外一种是在编译时的时候完成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。

    官方提供文档地址:http://docs.paralleluniverse.co/quasar/
  • 相关阅读:
    NopCommerce 增加 Customer Settings
    NopCommerce 增加 Customer Attributes
    [转]How to add new table in NopCommerce
    [转]教你一招
    [转]Oracle 修改或者删除临时表 ORA-14452: 试图创建, 更改或删除正在使用的临时表中的索引
    NopCommerce 发布时 Could not load file or assembly 'file:///...Autofac.3.5.2lib et40Autofac.dll' or one of its dependencies
    NopCommerce 关于Customer的会员类别及会员价处理 的尝试途径
    诸葛亮-诫子书
    [书目20161206]小狗钱钱的人生整理术
    [转]NopCommerce How to code my own payment method
  • 原文地址:https://www.cnblogs.com/z-test/p/9435847.html
Copyright © 2020-2023  润新知