Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Многие современные языки поддерживают работу с корутинами на уровне языка. Java в данный момент не поддерживает корутины, но есть надежды что в будущем все может измениться.
В С++20 планируется ввести поддержку для работы с корутинами.
Используя JNI мы можем писать корутины на С++ и использовать в Java коде.
Рассмотрим какие нативные корутины можно писать и как их использовать в Java коде.
Генератор позволяет создавать последовательность значений определенного типа, при этом значения генерируются лениво и синхронно.
Асинхронный Генератор позволяет создавать последовательность значений определенного типа, при этом значения генерируются лениво и асинхронно.
Задача (Task) производит асинхронное вычисление, которое выполняется лениво, при этом корутина не выполняется, пока задача не запустится явно.
Корутины можно использовать как легковесные потоки. При этом количество запущенных потоков в системе может быть ограничено, например не более 1000. А корутин можно запустить сколько угодно.
При запуске корутины, проверяется готова ли она. Если нет, то корутина приостанавливается и ОС передается обработчик на ее. В этот момент выполниться полезный кусок кода. Когда корутина готова, тогда выполняется возобновление корутины.
Как при запуске потока, корутине можно передать Runnable или Callable.
Таймер выполняет приостановку выполнения текущей задачи на требуемую длительность.
Можно использовать как замену Thread.sleep().
Также корутины можно применять для написания не блокирующего кода для работы с файловой системой, сетью и т.д.
Как можно видеть корутины облегчают написание асинхроного кода, позволяя выполнять части кода не блокируя поток.
Корутины которые планируют завести в С++20, появлятся в виде чистой языковой фичи.
Генераторы, задачи и другие корутиные планируются добавить в стандарт С++23 или позже.
Можно самому писать свои корутины или использовать уже готовой библиотекой, например cppcoro.
Компиляторы MVSC, Clang уже поддерживают корутины как расширение, а GCC только на стадии разработки.
Полный исходной код можно посмотреть на github: code
В С++20 планируется ввести поддержку для работы с корутинами.
Используя JNI мы можем писать корутины на С++ и использовать в Java коде.
Рассмотрим какие нативные корутины можно писать и как их использовать в Java коде.
Генератор позволяет создавать последовательность значений определенного типа, при этом значения генерируются лениво и синхронно.
/* 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);
}
Асинхронный Генератор позволяет создавать последовательность значений определенного типа, при этом значения генерируются лениво и асинхронно.
/* 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);
}
Задача (Task) производит асинхронное вычисление, которое выполняется лениво, при этом корутина не выполняется, пока задача не запустится явно.
Корутины можно использовать как легковесные потоки. При этом количество запущенных потоков в системе может быть ограничено, например не более 1000. А корутин можно запустить сколько угодно.
При запуске корутины, проверяется готова ли она. Если нет, то корутина приостанавливается и ОС передается обработчик на ее. В этот момент выполниться полезный кусок кода. Когда корутина готова, тогда выполняется возобновление корутины.
/* 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{};
Как при запуске потока, корутине можно передать Runnable или Callable.
/* Java code */
Coroutine.await(() -> {
int sum = 5 + 10;
});
Task<Integer> task = Coroutine.await(() -> {
int sum = 5 + 10;
return sum;
});
Таймер выполняет приостановку выполнения текущей задачи на требуемую длительность.
auto operator co_await(const std::chrono::system_clock::duration& duration) {
return timer{duration};
}
co_await 10ms;
Можно использовать как замену Thread.sleep().
Coroutine.await(10, TimeUnit.MILLISECONDS);
Также корутины можно применять для написания не блокирующего кода для работы с файловой системой, сетью и т.д.
Как можно видеть корутины облегчают написание асинхроного кода, позволяя выполнять части кода не блокируя поток.
Корутины которые планируют завести в С++20, появлятся в виде чистой языковой фичи.
Генераторы, задачи и другие корутиные планируются добавить в стандарт С++23 или позже.
Можно самому писать свои корутины или использовать уже готовой библиотекой, например cppcoro.
Компиляторы MVSC, Clang уже поддерживают корутины как расширение, а GCC только на стадии разработки.
Полный исходной код можно посмотреть на github: code