用Java实现协同路由

用Java实现协同路由,java,kotlin-coroutines,Java,Kotlin Coroutines,这个问题与我的问题有关。如我所怀疑的,如果Java中目前没有完整的协同路由实现,那么实现它们需要什么呢 正如我在该问题中所说,我知道以下几点: 您可以在后台将“协同路由”实现为线程/线程池 您可以在幕后使用JVM字节码做一些棘手的事情,以使协同路由成为可能 所谓的“达芬奇机器”JVM实现有一些原语,这些原语使协同路由不需要 字节码操作 也可能有各种基于JNI的协同路由方法 我将依次解决每个人的不足之处 基于线程的协同路由 这种“解决方案”是病态的。协同路由的全部目的是避免线程、锁定、内核调度等方

这个问题与我的问题有关。如我所怀疑的,如果Java中目前没有完整的协同路由实现,那么实现它们需要什么呢

正如我在该问题中所说,我知道以下几点:

  • 您可以在后台将“协同路由”实现为线程/线程池
  • 您可以在幕后使用JVM字节码做一些棘手的事情,以使协同路由成为可能
  • 所谓的“达芬奇机器”JVM实现有一些原语,这些原语使协同路由不需要 字节码操作
  • 也可能有各种基于JNI的协同路由方法
  • 我将依次解决每个人的不足之处

    基于线程的协同路由 这种“解决方案”是病态的。协同路由的全部目的是避免线程、锁定、内核调度等方面的开销。协同路由应该是轻快的,并且只在用户空间中执行。在具有严格限制的全倾斜线程中实现它们可以消除所有优势

    JVM字节码操作 这个解决方案更实用,尽管有点难以实现。这与跳转到C语言中的协同程序库的汇编语言(其中有多少是可以工作的)大致相同,其优点是您只有一个体系结构需要考虑和正确使用

    它还将您限制为仅在完全兼容的JVM堆栈上运行代码(例如,这意味着没有Android),除非您能够找到在不兼容的堆栈上执行相同操作的方法。但是,如果您确实找到了这样做的方法,那么现在您的系统复杂性和测试需求已经翻了一番

    达芬奇机器 达芬奇机器对于实验来说很酷,但由于它不是一个标准的JVM,所以它的特性不会在任何地方都可用。事实上,我怀疑大多数生产环境都会特别禁止使用达芬奇机器。因此,我可以用它来做一些很酷的实验,但不适用于我希望发布到现实世界的任何代码

    这还增加了一个类似于上面JVM字节码操作解决方案的问题:无法在替代堆栈(如Android)上工作

    JNI实现 这个解决方案使得在Java中实现这一点毫无意义。CPU和操作系统的每一个组合都需要独立的测试,每一个组合都有可能导致令人沮丧的微妙故障。当然,我也可以将自己完全限制在一个平台上,但这也使得用Java做事情完全没有意义

    所以

    有没有办法不用这四种技术中的一种在Java中实现协同路由?或者我会被迫使用这四种气味最少的方法(JVM操作)来代替


    编辑以添加:


    为了确保混乱得到控制,这是一个相关的问题,但不是同一个问题。该公司正在寻找一个现有的实现,以避免不必要地重新发明轮子。这是一个关于如果另一个被证明无法回答,如何在Java中实现协同路由的问题。这样做的目的是在不同的线程上保留不同的问题。

    我想看看这个:,它非常有趣,应该是一个很好的起点。当然,我们使用Java是为了做得更好(或者更糟,因为没有宏:)

    根据我对协同程序的理解,通常有一个生产者和一个消费者协同程序(或者至少这是最常见的模式)。但从语义上讲,你不希望制作人打电话给消费者,或者visa打电话给消费者,因为这会引入不对称。但是考虑到基于堆栈的语言的工作方式,我们需要有人来做这项工作

    下面是一个非常简单的类型层次结构:

    public interface CoroutineProducer<T>
    {
        public T Produce();
        public boolean isDone();
    }
    
    public interface CoroutineConsumer<T>
    {
        public void Consume(T t);
    }
    
    public class CoroutineManager
    {
        public static Execute<T>(CoroutineProducer<T> prod, CoroutineConsumer<T> con)
        {
            while(!prod.IsDone()) // really simple
            {
                T d = prod.Produce();
                con.Consume(d);
            }
        }
    }
    
    我们需要抽象局部变量,如
    is_done
    other_state
    ,我们需要抽象while循环本身,因为我们的
    yield
    like操作不会使用堆栈。因此,让我们创建一个while循环抽象和相关类:

    enum WhileState {BREAK, CONTINUE, YIELD}
    abstract class WhileLoop<T>
    {
        private boolean is_done;
        public boolean isDone() { return is_done;}
        private T rval;
        public T getReturnValue() {return rval;} 
        protected void setReturnValue(T val)
        {
            rval = val;
        }
    
    
        public T loop()
        {
            while(true)
            {
                WhileState state = execute();
                if(state == WhileState.YIELD)
                    return getReturnValue();
                else if(state == WhileState.BREAK)
                        {
                           is_done = true;
                    return null;
                        }
            }
        }
        protected abstract WhileState execute();
    }
    
    enum WhileState{BREAK,CONTINUE,YIELD}
    抽象类WhileLoop
    {
    私有布尔完成;
    公共布尔isDone(){return is_done;}
    私人旅行;
    public T getReturnValue(){return rval;}
    受保护的void setReturnValue(T val)
    {
    rval=val;
    }
    公共T循环()
    {
    while(true)
    {
    WhileState=execute();
    if(state==WhileState.YIELD)
    返回getReturnValue();
    else if(state==WhileState.BREAK)
    {
    是否完成=正确;
    返回null;
    }
    }
    }
    受保护的抽象WhileState execute();
    }
    
    这里的基本技巧是将局部变量移动为变量,并将作用域块转换为类,从而使我们能够在产生返回值后“重新进入”我们的“循环”

    现在来实现我们的生产者

    public class SampleProducer : CoroutineProducer<Object>
    {
        private WhileLoop<Object> loop;//our control structures become state!!
        public SampleProducer()
        {
            loop = new WhileLoop()
            {
                private int other_state;//our local variables become state of the control structure
                protected WhileState execute() 
                {
                    //this implements a single iteration of the loop
                    if(is_done) return WhileState.BREAK;
                    //read input
                    //parse input
                    Object calcluated_value = ...;
                    //update is_done, figure out if we want to continue
                    setReturnValue(calculated_value);
                    return WhileState.YIELD;
                }
            };
        }
        public Object Produce()
        {
            Object val = loop.loop();
            return val;
        }
        public boolean isDone()
        {
            //we are done when the loop has exited
            return loop.isDone();
        }
    }
    
    public类样本生产者:CoroutineProducer
    {
    私有WhileLoop循环;//我们的控制结构变成状态!!
    公共样本生产者()
    {
    loop=newwhileloop()
    {
    private int other_state;//我们的局部变量成为控制结构的状态
    受保护的WhileState执行()
    {
    //这实现了循环的单个迭代
    如果(完成)返回WhileState.BREAK;
    //读取输入
    //解析输入
    对象calcluated_值=。。。;
    //更新已完成,请确定是否要继续
    setReturnValue(计算值);
    收益率;
    }
    };
    }
    公共对象生成()
    {
    奥布耶
    
    public class SampleProducer : CoroutineProducer<Object>
    {
        private WhileLoop<Object> loop;//our control structures become state!!
        public SampleProducer()
        {
            loop = new WhileLoop()
            {
                private int other_state;//our local variables become state of the control structure
                protected WhileState execute() 
                {
                    //this implements a single iteration of the loop
                    if(is_done) return WhileState.BREAK;
                    //read input
                    //parse input
                    Object calcluated_value = ...;
                    //update is_done, figure out if we want to continue
                    setReturnValue(calculated_value);
                    return WhileState.YIELD;
                }
            };
        }
        public Object Produce()
        {
            Object val = loop.loop();
            return val;
        }
        public boolean isDone()
        {
            //we are done when the loop has exited
            return loop.isDone();
        }
    }
    
    import java.lang.ref.WeakReference;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.*;
    import java.util.concurrent.atomic.AtomicBoolean;
    import java.util.concurrent.atomic.AtomicReference;
    
    class CorRunRAII {
        private final List<WeakReference<? extends CorRun>> resources = new ArrayList<>();
    
        public CorRunRAII add(CorRun resource) {
            if (resource == null) {
                return this;
            }
            resources.add(new WeakReference<>(resource));
    
            return this;
        }
    
        public CorRunRAII addAll(List<? extends CorRun> arrayList) {
            if (arrayList == null) {
                return this;
            }
            for (CorRun corRun : arrayList) {
                add(corRun);
            }
    
            return this;
        }
    
        @Override
        protected void finalize() throws Throwable {
            super.finalize();
    
            for (WeakReference<? extends CorRun> corRunWeakReference : resources) {
                CorRun corRun = corRunWeakReference.get();
                if (corRun != null) {
                    corRun.stop();
                }
            }
        }
    }
    
    class CorRunYieldReturn<ReceiveType, YieldReturnType> {
        public final AtomicReference<ReceiveType> receiveValue;
        public final LinkedBlockingDeque<AtomicReference<YieldReturnType>> yieldReturnValue;
    
        CorRunYieldReturn(AtomicReference<ReceiveType> receiveValue, LinkedBlockingDeque<AtomicReference<YieldReturnType>> yieldReturnValue) {
            this.receiveValue = receiveValue;
            this.yieldReturnValue = yieldReturnValue;
        }
    }
    
    interface CorRun<ReceiveType, YieldReturnType> extends Runnable, Callable<YieldReturnType> {
        boolean start();
        void stop();
        void stop(final Throwable throwable);
        boolean isStarted();
        boolean isEnded();
        Throwable getError();
    
        ReceiveType getReceiveValue();
        void setResultForOuter(YieldReturnType resultForOuter);
        YieldReturnType getResultForOuter();
    
        YieldReturnType receive(ReceiveType value);
        ReceiveType yield();
        ReceiveType yield(YieldReturnType value);
        <TargetReceiveType, TargetYieldReturnType> TargetYieldReturnType yieldFrom(final CorRun<TargetReceiveType, TargetYieldReturnType> another);
        <TargetReceiveType, TargetYieldReturnType> TargetYieldReturnType yieldFrom(final CorRun<TargetReceiveType, TargetYieldReturnType> another, final TargetReceiveType value);
    }
    
    abstract class CorRunSync<ReceiveType, YieldReturnType> implements CorRun<ReceiveType, YieldReturnType> {
    
        private ReceiveType receiveValue;
        public final List<WeakReference<CorRun>> potentialChildrenCoroutineList = new ArrayList<>();
    
        // Outside
    
        private AtomicBoolean isStarted = new AtomicBoolean(false);
        private AtomicBoolean isEnded = new AtomicBoolean(false);
        private Throwable error;
    
        private YieldReturnType resultForOuter;
    
        @Override
        public boolean start() {
    
            boolean isStarted = this.isStarted.getAndSet(true);
            if ((! isStarted)
                    && (! isEnded())) {
                receive(null);
            }
    
            return isStarted;
        }
    
        @Override
        public void stop() {
            stop(null);
        }
    
        @Override
        public void stop(Throwable throwable) {
            isEnded.set(true);
            if (throwable != null) {
                error = throwable;
            }
    
            for (WeakReference<CorRun> weakReference : potentialChildrenCoroutineList) {
                CorRun child = weakReference.get();
                if (child != null) {
                    child.stop();
                }
            }
        }
    
        @Override
        public boolean isStarted() {
            return isStarted.get();
        }
    
        @Override
        public boolean isEnded() {
            return isEnded.get();
        }
    
        @Override
        public Throwable getError() {
            return error;
        }
    
        @Override
        public ReceiveType getReceiveValue() {
            return receiveValue;
        }
    
        @Override
        public void setResultForOuter(YieldReturnType resultForOuter) {
            this.resultForOuter = resultForOuter;
        }
    
        @Override
        public YieldReturnType getResultForOuter() {
            return resultForOuter;
        }
    
        @Override
        public synchronized YieldReturnType receive(ReceiveType value) {
            receiveValue = value;
    
            run();
    
            return getResultForOuter();
        }
    
        @Override
        public ReceiveType yield() {
            return yield(null);
        }
    
        @Override
        public ReceiveType yield(YieldReturnType value) {
            resultForOuter = value;
            return receiveValue;
        }
    
        @Override
        public <TargetReceiveType, TargetYieldReturnType> TargetYieldReturnType yieldFrom(CorRun<TargetReceiveType, TargetYieldReturnType> another) {
            return yieldFrom(another, null);
        }
    
        @Override
        public <TargetReceiveType, TargetYieldReturnType> TargetYieldReturnType yieldFrom(CorRun<TargetReceiveType, TargetYieldReturnType> another, TargetReceiveType value) {
            if (another == null || another.isEnded()) {
                throw new RuntimeException("Call null or isEnded coroutine");
            }
    
            potentialChildrenCoroutineList.add(new WeakReference<CorRun>(another));
    
            synchronized (another) {
                boolean isStarted = another.start();
                boolean isJustStarting = ! isStarted;
                if (isJustStarting && another instanceof CorRunSync) {
                    return another.getResultForOuter();
                }
    
                return another.receive(value);
            }
        }
    
        @Override
        public void run() {
            try {
                this.call();
            }
            catch (Exception e) {
                e.printStackTrace();
    
                stop(e);
                return;
            }
        }
    }
    
    abstract class CorRunThread<ReceiveType, YieldReturnType> implements CorRun<ReceiveType, YieldReturnType> {
    
        private final ExecutorService childExecutorService = newExecutorService();
        private ExecutorService executingOnExecutorService;
    
        private static final CorRunYieldReturn DUMMY_COR_RUN_YIELD_RETURN = new CorRunYieldReturn(new AtomicReference<>(null), new LinkedBlockingDeque<AtomicReference>());
    
        private final CorRun<ReceiveType, YieldReturnType> self;
        public final List<WeakReference<CorRun>> potentialChildrenCoroutineList;
        private CorRunYieldReturn<ReceiveType, YieldReturnType> lastCorRunYieldReturn;
    
        private final LinkedBlockingDeque<CorRunYieldReturn<ReceiveType, YieldReturnType>> receiveQueue;
    
        // Outside
    
        private AtomicBoolean isStarted = new AtomicBoolean(false);
        private AtomicBoolean isEnded = new AtomicBoolean(false);
        private Future<YieldReturnType> future;
        private Throwable error;
    
        private final AtomicReference<YieldReturnType> resultForOuter = new AtomicReference<>();
    
        CorRunThread() {
            executingOnExecutorService = childExecutorService;
    
            receiveQueue = new LinkedBlockingDeque<>();
            potentialChildrenCoroutineList = new ArrayList<>();
    
            self = this;
        }
    
        @Override
        public void run() {
            try {
                self.call();
            }
            catch (Exception e) {
                stop(e);
                return;
            }
    
            stop();
        }
    
        @Override
        public abstract YieldReturnType call();
    
        @Override
        public boolean start() {
            return start(childExecutorService);
        }
    
        protected boolean start(ExecutorService executorService) {
            boolean isStarted = this.isStarted.getAndSet(true);
            if (!isStarted) {
                executingOnExecutorService = executorService;
                future = (Future<YieldReturnType>) executingOnExecutorService.submit((Runnable) self);
            }
            return isStarted;
        }
    
        @Override
        public void stop() {
            stop(null);
        }
    
        @Override
        public void stop(final Throwable throwable) {
            if (throwable != null) {
                error = throwable;
            }
            isEnded.set(true);
    
            returnYieldValue(null);
            // Do this for making sure the coroutine has checked isEnd() after getting a dummy value
            receiveQueue.offer(DUMMY_COR_RUN_YIELD_RETURN);
    
            for (WeakReference<CorRun> weakReference : potentialChildrenCoroutineList) {
                CorRun child = weakReference.get();
                if (child != null) {
                    if (child instanceof CorRunThread) {
                        ((CorRunThread)child).tryStop(childExecutorService);
                    }
                }
            }
    
            childExecutorService.shutdownNow();
        }
    
        protected void tryStop(ExecutorService executorService) {
            if (this.executingOnExecutorService == executorService) {
                stop();
            }
        }
    
        @Override
        public boolean isEnded() {
            return isEnded.get() || (
                    future != null && (future.isCancelled() || future.isDone())
                    );
        }
    
        @Override
        public boolean isStarted() {
            return isStarted.get();
        }
    
        public Future<YieldReturnType> getFuture() {
            return future;
        }
    
        @Override
        public Throwable getError() {
            return error;
        }
    
        @Override
        public void setResultForOuter(YieldReturnType resultForOuter) {
            this.resultForOuter.set(resultForOuter);
        }
    
        @Override
        public YieldReturnType getResultForOuter() {
            return this.resultForOuter.get();
        }
    
        @Override
        public YieldReturnType receive(ReceiveType value) {
    
            LinkedBlockingDeque<AtomicReference<YieldReturnType>> yieldReturnValue = new LinkedBlockingDeque<>();
    
            offerReceiveValue(value, yieldReturnValue);
    
            try {
                AtomicReference<YieldReturnType> takeValue = yieldReturnValue.take();
                return takeValue == null ? null : takeValue.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            return null;
        }
    
        @Override
        public ReceiveType yield() {
            return yield(null);
        }
    
        @Override
        public ReceiveType yield(final YieldReturnType value) {
            returnYieldValue(value);
    
            return getReceiveValue();
        }
    
        @Override
        public <TargetReceiveType, TargetYieldReturnType> TargetYieldReturnType yieldFrom(final CorRun<TargetReceiveType, TargetYieldReturnType> another) {
            return yieldFrom(another, null);
        }
    
        @Override
        public <TargetReceiveType, TargetYieldReturnType> TargetYieldReturnType yieldFrom(final CorRun<TargetReceiveType, TargetYieldReturnType> another, final TargetReceiveType value) {
            if (another == null || another.isEnded()) {
                throw new RuntimeException("Call null or isEnded coroutine");
            }
    
            boolean isStarted = false;
            potentialChildrenCoroutineList.add(new WeakReference<CorRun>(another));
    
            synchronized (another) {
                if (another instanceof CorRunThread) {
                    isStarted = ((CorRunThread)another).start(childExecutorService);
                }
                else {
                    isStarted = another.start();
                }
    
                boolean isJustStarting = ! isStarted;
                if (isJustStarting && another instanceof CorRunSync) {
                    return another.getResultForOuter();
                }
    
                TargetYieldReturnType send = another.receive(value);
                return send;
            }
        }
    
        @Override
        public ReceiveType getReceiveValue() {
    
            setLastCorRunYieldReturn(takeLastCorRunYieldReturn());
    
            return lastCorRunYieldReturn.receiveValue.get();
        }
    
        protected void returnYieldValue(final YieldReturnType value) {
            CorRunYieldReturn<ReceiveType, YieldReturnType> corRunYieldReturn = lastCorRunYieldReturn;
            if (corRunYieldReturn != null) {
                corRunYieldReturn.yieldReturnValue.offer(new AtomicReference<>(value));
            }
        }
    
        protected void offerReceiveValue(final ReceiveType value, LinkedBlockingDeque<AtomicReference<YieldReturnType>> yieldReturnValue) {
            receiveQueue.offer(new CorRunYieldReturn(new AtomicReference<>(value), yieldReturnValue));
        }
    
        protected CorRunYieldReturn<ReceiveType, YieldReturnType> takeLastCorRunYieldReturn() {
            try {
                return receiveQueue.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            return null;
        }
    
        protected void setLastCorRunYieldReturn(CorRunYieldReturn<ReceiveType,YieldReturnType> lastCorRunYieldReturn) {
            this.lastCorRunYieldReturn = lastCorRunYieldReturn;
        }
    
        protected ExecutorService newExecutorService() {
            return Executors.newCachedThreadPool(getThreadFactory());
        }
    
        protected ThreadFactory getThreadFactory() {
            return new ThreadFactory() {
                @Override
                public Thread newThread(final Runnable runnable) {
                    Thread thread = new Thread(runnable);
                    thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                        @Override
                        public void uncaughtException(Thread thread, Throwable throwable) {
                            throwable.printStackTrace();
                            if (runnable instanceof CorRun) {
                                CorRun self = (CorRun) runnable;
                                self.stop(throwable);
                                thread.interrupt();
                            }
                        }
                    });
                    return thread;
                }
            };
        }
    }
    
    class Fib extends CorRunThread<Integer, Integer> {
    
        @Override
        public Integer call() {
            Integer times = getReceiveValue();
            do {
                int a = 1, b = 1;
                for (int i = 0; times != null && i < times; i++) {
                    int temp = a + b;
                    a = b;
                    b = temp;
                }
                // A pythonic "yield", i.e., it returns `a` to the caller and waits `times` value from the next caller
                times = yield(a);
            } while (! isEnded());
    
            setResultForOuter(Integer.MAX_VALUE);
            return getResultForOuter();
        }
    }
    
    class MainRun extends CorRunThread<String, String> {
    
        @Override
        public String call() {
    
            // The fib coroutine would be recycled by its parent
            // (no requirement to call its start() and stop() manually)
            // Otherwise, if you want to share its instance and start/stop it manually,
            // please start it before being called by yieldFrom() and stop it in the end.
            Fib fib = new Fib();
            String result = "";
            Integer current;
            int times = 10;
            for (int i = 0; i < times; i++) {
    
                // A pythonic "yield from", i.e., it calls fib with `i` parameter and waits for returned value as `current`
                current = yieldFrom(fib, i);
    
                if (fib.getError() != null) {
                    throw new RuntimeException(fib.getError());
                }
    
                if (current == null) {
                    continue;
                }
    
                if (i > 0) {
                    result += ",";
                }
                result += current;
    
            }
    
            setResultForOuter(result);
    
            return result;
        }
    }
    
    class Fib extends CorRunSync<Integer, Integer> {
    
        @Override
        public Integer call() {
            Integer times = getReceiveValue();
    
            int a = 1, b = 1;
            for (int i = 0; times != null && i < times; i++) {
                int temp = a + b;
                a = b;
                b = temp;
            }
            yield(a);
    
            return getResultForOuter();
        }
    }
    
    class MainRun extends CorRunSync<String, String> {
    
        @Override
        public String call() {
    
            CorRun<Integer, Integer> fib = null;
            try {
                fib = new Fib();
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            String result = "";
            Integer current;
            int times = 10;
            for (int i = 0; i < times; i++) {
    
                current = yieldFrom(fib, i);
    
                if (fib.getError() != null) {
                    throw new RuntimeException(fib.getError());
                }
    
                if (current == null) {
                    continue;
                }
    
                if (i > 0) {
                    result += ",";
                }
                result += current;
            }
    
            stop();
            setResultForOuter(result);
    
            if (Utils.isEmpty(result)) {
                throw new RuntimeException("Error");
            }
    
            return result;
        }
    }
    
    // Run the entry coroutine
    MainRun mainRun = new MainRun();
    mainRun.start();
    
    // Wait for mainRun ending for 5 seconds
    long startTimestamp = System.currentTimeMillis();
    while(!mainRun.isEnded()) {
        if (System.currentTimeMillis() - startTimestamp > TimeUnit.SECONDS.toMillis(5)) {
            throw new RuntimeException("Wait too much time");
        }
    }
    // The result should be "1,1,2,3,5,8,13,21,34,55"
    System.out.println(mainRun.getResultForOuter());
    
    static final ContinuationScope scope=new ContinuationScope("TST");
    
    public static void main(String[] args) {
        example1();
    }
    
    // *********************************************************************
    // *** EXAMPLE 1: Co-routine with three active phases:
    // *********************************************************************
    
    public static void example1() {
        
        Continuation coroutine=new Continuation(scope,new Runnable() {
            public void run() {
                System.out.println("Part 1 - Statements");
                Continuation.yield(scope); // DETACH 1
                System.out.println("Part 2 - Statements");
                Continuation.yield(scope); // DETACH 2
                System.out.println("Part 3 - Statements");
            }});
        
        
        coroutine.run(); // Vil utføre Part 1.
        System.out.println("Returns here after first DETACH(Yield)");
        coroutine.run(); // Vil utføre Part 2.
        System.out.println("Returns here after second DETACH(Yield)");
        coroutine.run(); // Vil utføre Part 3.
        System.out.println("Returns here after 'FINAL END'");
        System.out.println("Next line should be: IllegalStateException: Continuation terminated");
        coroutine.run(); // IllegalStateException: Continuation terminated
    }