Java, coroutines (quasar) python of Coroutine

  First, we simply put in front a bit, coroutine principle Python. Add here Java coroutine implementation process. There is a need to view the python of coroutines .

  Two, Java coroutine, in fact, doing Java for so long I have not heard how things Java coroutine, but there have been hearing the concept of micro-threaded / coroutines, this is not the time to learn Python contact the word coroutine. Then come to understand Java return coroutine problem, but saw a lot of information, the official website and find many places that are not related to what coroutines, there is no recourse but to learn something related to coroutines by strong community.

  Third, the main concern here is: Quasar.

  Objective 1) coroutines: When we use multithreading, if there is a long period of I / O operations. This time has been the thread is blocked, if the thread a lot of time, there will be many threads in an idle state, resulting in a resource application is not complete. Opposing coroutine not the same, a plurality of tasks in a single thread back and forth for a long time if the self appears I / O operation, so that a current allowed coroutine scheduling, perform the next task. Of course, all possible tasks, all the cards on the same point, but this is only for single-threaded, when all the data is returned to normal, will also address the current I / O operations.

  2) multi-threaded test (here using one million threads to test memory footprint) 

        for (int i = 0; i < 1000000; i++) {
            new Thread(() -> {
                try {
                    Thread.sleep(100000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }    

  result:

  Direct stuck a memory overflow

  

  One can imagine that if one million threads exist, the cost is how much.

  3) Test coroutine

  a, Ali cloud search dependencies

     <dependency>
            <groupId>co.paralleluniverse</groupId>
            <artifactId>quasar-core</artifactId>
            <version>0.7.9</version>
            <classifier>jdk8</classifier>
        </dependency>

  b, test memory footprint

  public  static  void main (String [] args) throws Exception {
         // use blocking queue to obtain the result. 
        A LinkedBlockingQueue <Fiber <Integer >> fiberQueue = new new a LinkedBlockingQueue <> (); 
        the DateTimeFormatter Formatter = DateTimeFormatter.ofPattern ( "the MM-dd-YYYY HH: mm: SS" );
         for ( int I = 0; I <1000000; I ++ ) {
             int Finali = I;
             // here Fiber bit like Callable, data can be returned 
            Fiber <Integer> = Fiber new new Fiber <> ((SuspendableCallable <Integer>) () ->// here for testing memory footprint 
                Fiber.sleep (100000 ); 
                System.out.println ( "IN-" Finali + + "-" + . LocalDateTime.now () the format (Formatter));
                 return Finali; 
            }) ; 
            // begin 
            fiber.start ();
             // enqueued 
            fiberQueue.add (Fiber); 
        } 
        the while ( to true ) {
             // blocking 
            Fiber <Integer> = Fiber fiberQueue.take (); 
            System.out.println ( " OUT- "fiber.get + () +" - "+ LocalDateTime.now () the format (Formatter));. 
        } 
    }

  result:

  stack:

  

   Estimation: about 1 G.

  RAM:

  

  Estimate: about 1 G, that is, every fiber occupy about 1Kb.

   c, normal test

  Modify the following parameters:

    public  static  void main (String [] args) throws Exception {
         // use blocking queue to obtain the result. 
        A LinkedBlockingQueue <Fiber <Integer >> fiberQueue = new new a LinkedBlockingQueue <> (); 
        the DateTimeFormatter Formatter = DateTimeFormatter.ofPattern ( "the MM-dd-YYYY HH: mm: SS" );
         for ( int I = 0; I <10; I ++ ) {
             int Finali = I;
             // here Fiber bit like Callable, data can be returned 
            Fiber <Integer> = Fiber new new Fiber <> ((SuspendableCallable <Integer>) () ->Here for testing memory footprint 
                Fiber.sleep (1000 ); 
                System.out.println ( "IN-" Finali + + "-" + LocalDateTime.now () the format (Formatter).);
                 Return Finali; 
            }); 
            / / started 
            fiber.start ();
             // enqueued 
            fiberQueue.add (Fiber); 
        } 
        the while ( to true ) {
             // blocking 
            Fiber <Integer> = Fiber fiberQueue.take (); 
            System.out.println ( "OUT- "fiber.get + () +" - "+ LocalDateTime.now () the format (Formatter));. 
        }
    }

  result:

  

  4) It can be seen concurrent state is very good, of course, this is just more tasks to perform it.

  Fourth, through the above test, it can be seen, quasar in Fiber, much like Callable usage, but also in reducing the memory footprint on top of a lot, of course, the number of stacks is indeed a lot, but acceptable.

  Still to be described: coroutine manner used for more I / O intensive operations. Or compute intensive use threads more reasonable.

  Fifth, the principle, I guess it looked forward to the source, high complexity, not to get to the bottom here.

  Principle Reference: gen Java programming (a): Java in the coroutine

  1, Quasar is in fact a continuation of Fiber, he could be the definition of Quasar scheduled scheduler, a continuation record the status of running instances, and will be interrupted at any time, and will then resume where he had been interrupted. Quasar fact by modifying the bytecode for this purpose, so when Quasar run the program, you need to modify your code at runtime via java-agent, of course, can do it during compilation. golang built its own scheduler, Quasar is used by default ForkJoinPool JDK7 only after this, the thread pool has a work-stealing function to when the scheduler. work-stealing is very important, because you do not know what Fiber will first executed, and the work-stealing can steal a dynamic context come from the other, and so the queue, so you can maximize the use of CPU resources.

  2, that here you will ask, Quasar how to modify the bytecode know what does, in fact, very simple, Quasar will scan through java-agent at run time which method is interrupted, and it will be called before the method and schedule insert some logic in the continuation method after, if you define @Suspendable comment on the way, that Quasar would call a method similar to the annotated do the following things.

  3、这里假设你在方法f上定义了@Suspendable,同时去调用了有同样注解的方法g,那么所有调用f的方法会插入一些字节码,这些字节码的逻辑就是记录当前Fiber栈上的状态,以便在未来可以动态的恢复。(Fiber类似线程也有自己的栈)。在suspendable方法链内Fiber的父类会调用Fiber.park,这样会抛出SuspendExecution异常,从而来停止线程的运行,好让Quasar的调度器执行调度。这里的SuspendExecution会被Fiber自己捕获,业务层面上不应该捕获到。如果Fiber被唤醒了(调度器层面会去调用Fiber.unpark),那么f会在被中断的地方重新被调用(这里Fiber会知道自己在哪里被中断),同时会把g的调用结果(g会return结果)插入到f的恢复点,这样看上去就好像g的return是f的local variables了,从而避免了callback嵌套。

  4、上面啰嗦了一大堆,其实简单点讲就是,想办法让运行中的线程栈停下来,好让Quasar的调度器介入。JVM线程中断的条件只有两个,一个是抛异常,另外一个就是return。这里Quasar就是通过抛异常的方式来达到的,所以你会看到我上面的代码会抛出SuspendExecution。但是如果你真捕获到这个异常,那就说明有问题了,所以一般会这么写。

Guess you like

Origin www.cnblogs.com/ll409546297/p/10945119.html