Utilisation de coroutines natives en Java

De nombreuses langues modernes prennent en charge le travail avec les coroutines au niveau de la langue. Java ne prend actuellement pas en charge les coroutines, mais il y a de l'espoir que les choses puissent changer à l'avenir.

En C ++ 20, il est prévu d'introduire la prise en charge du travail avec les coroutines.
En utilisant JNI, nous pouvons écrire des coroutines en C ++ et utiliser en code Java.

Examinons quelles coroutines natives peuvent être écrites et comment les utiliser dans du code Java.

Le générateur vous permet de créer une séquence de valeurs d'un certain type, tandis que les valeurs sont générées paresseusement et de manière synchrone.

/* 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); } 

Le générateur asynchrone vous permet de créer une séquence de valeurs d'un certain type, tandis que les valeurs sont générées de manière paresseuse et asynchrone.

  /* 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); } 

La tâche effectue un calcul asynchrone, qui est effectué paresseusement, tandis que la coroutine n'est pas exécutée jusqu'à ce que la tâche démarre explicitement.

Les coroutines peuvent être utilisées comme flux lumineux. Dans ce cas, le nombre de threads en cours d'exécution dans le système peut être limité, par exemple, pas plus de 1000. Et la coroutine peut être exécutée autant que vous le souhaitez.

Lors du démarrage d'une coroutine, il est vérifié si elle est prête. Sinon, la coroutine est suspendue et le système d'exploitation lui transmet le gestionnaire. À ce stade, un morceau de code utile est exécuté. Lorsque la coroutine est prête, le renouvellement de la coroutine est effectué.

  /* 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{}; 

Comme lors du démarrage d'un thread, vous pouvez passer Runnable ou Callable à une coroutine.

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

Le temporisateur suspend la tâche en cours pendant la durée requise.

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

Peut être utilisé en remplacement de Thread.sleep ().

  Coroutine.await(10, TimeUnit.MILLISECONDS); 

Les coroutines peuvent également être utilisées pour écrire du code non bloquant pour travailler avec le système de fichiers, le réseau, etc.

Comme vous pouvez le voir, les coroutines facilitent l'écriture de code asynchrone, permettant l'exécution de parties du code sans bloquer le flux.

Les coroutines qu'ils prévoient de démarrer en C ++ 20 apparaîtront comme des fonctionnalités de langage pur.
Des générateurs, des tâches et d'autres coroutines devraient être ajoutés à la norme C ++ 23 ou version ultérieure.
Vous pouvez écrire vos propres coroutines vous-même ou utiliser une bibliothèque prête à l'emploi, par exemple cppcoro .

Les compilateurs MVSC, Clang prennent déjà en charge les coroutines en tant qu'extension et GCC n'en est qu'au stade de développement.

Le code source complet peut être consulté sur github: code

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


All Articles