Usando corotinas nativas em Java

Muitos idiomas modernos oferecem suporte ao trabalho com corotinas no nível do idioma. Atualmente, o Java não suporta corotinas, mas há esperança de que as coisas possam mudar no futuro.

No C ++ 20, está planejado introduzir suporte para trabalhar com corotinas.
Usando JNI, podemos escrever corotinas em C ++ e usar no código Java.

Vamos considerar quais corotinas nativas podem ser escritas e como usá-las no código Java.

O gerador permite criar uma sequência de valores de um determinado tipo, enquanto os valores são gerados de forma lenta e síncrona.

/* C++ code */ generator<int> generate(int count) { for (int i = 0; i < count; i++) { co_yield i; } } 

  /* Java code */ Generator<Integer> gen1 = Coroutine.yield(5); Generator<Float> gen2 = Coroutine.yield(1f, 5); Generator<Double> gen3 = Coroutine.yield(v -> v * 2, 1d, 5); for (int item : gen1) { System.out.println("yield value: " + item); } 

O gerador assíncrono permite criar uma sequência de valores de um determinado tipo, enquanto os valores são gerados de forma lenta e assíncrona.

  /* C++ code */ async_generator<int> generate(int count) { for (int i = 0; i < count; i++) { co_await 1s; co_yield i; } } 

  /* Java code */ Generator<Integer> gen1 = Coroutine.yieldAsync(5); Generator<Float> gen2 = Coroutine.yieldAsync(1f, 5); Generator<Double> gen3 = Coroutine.yieldAsync(v -> v * 2, 1d, 5); for (int item : gen1) { System.out.println("yield value: " + item); } 

A tarefa executa o cálculo assíncrono, que é realizado preguiçosamente, enquanto a corotina não é executada até que a tarefa seja iniciada explicitamente.

As corotinas podem ser usadas como fluxos de luz. Nesse caso, o número de threads em execução no sistema pode ser limitado, por exemplo, não mais que 1000. E a corotina pode ser executada quantas vezes você quiser.

Ao iniciar uma corotina, é verificado se está pronta. Caso contrário, a rotina é pausada e o sistema operacional passa o manipulador para ele. Nesse ponto, um pedaço de código útil é executado. Quando a corotina está pronta, a renovação da corotina é realizada.

  /* C++ code */ struct awaiter { bool await_ready() const { return false; } void await_resume() {} void await_suspend(std::coroutine_handle<> handler) { /* invoke java/jni code */ if (!handler.done()) { handler.resume(); } } }; co_await awaiter{}; 

Como ao iniciar um encadeamento, você pode passar Runnable ou Callable para uma corotina.

  /* Java code */ Coroutine.await(() -> { int sum = 5 + 10; }); Task<Integer> task = Coroutine.await(() -> { int sum = 5 + 10; return sum; }); 

O cronômetro pausa a tarefa atual pela duração necessária.

  auto operator co_await(const std::chrono::system_clock::duration& duration) { return timer{duration}; } co_await 10ms; 

Pode ser usado como um substituto para Thread.sleep ().

  Coroutine.await(10, TimeUnit.MILLISECONDS); 

As corotinas também podem ser usadas para escrever código sem bloqueio para trabalhar com o sistema de arquivos, a rede etc.

Como você pode ver, as corotinas facilitam a escrita de código assíncrono, permitindo que partes do código sejam executadas sem bloquear o fluxo.

As corotinas que planejam iniciar no C ++ 20 aparecerão como recursos de linguagem pura.
Geradores, tarefas e outras corotinas estão planejadas para serem adicionadas ao padrão C ++ 23 ou posterior.
Você mesmo pode escrever suas próprias rotinas ou usar uma biblioteca pronta, por exemplo, cppcoro .

Os compiladores MVSC, Clang já suportam corotinas como uma extensão e o GCC está apenas no estágio de desenvolvimento.

O código fonte completo pode ser visualizado no github: code

Source: https://habr.com/ru/post/pt474394/


All Articles