История изменений
Исправление dissident, (текущая версия) :
Под полингом я имел в виду не полинг состояния корутин, а полинг состояния абстракций с которыми они работают.
А если они вовсе не работают ни с какими абстракциями как пример Lua выше а просто делают что-то -> отдают управление по yield -> делают что-то -> отдают управление по yield…
Где в этом примере полинг?
Очевидно, что в такой ситуации корутины используют какую-то lock free структуру для обработки cpu bound задач. В такой ситуации не работал с корутинами, не знаю есть ли в этом случае профит.
Зачем корутинам (стэковым или безстэковым) lock-free структуры, если они выполняются в одном трэде?
В точках создания корутин компилятор должен просто сгенерировать (или программист написать, если корутины реализованы в виде внешней библиотеки) код, который создаст структуру/ucontext для корутины.
В точках yield()/resume() компилятор должен просто сгенерировать (или программист написать) код, который вызовет что-нибудь вроде swapcontext().
AFAIU так как трэд один, никакой полинг/lock-free структуры/мутексы не нужны.
PS я имею ввиду здесь корутины, которые просто делают yield()/resume() без всяких async операций вроде socket::read() «под ними». Т.е., например, тут трэд один и никакой полинг не нужен:
coroutine_type coroutine()
{
coroutine_type cor_type;
int a, b;
while (...)
{
do_smth_a_little_bit();
// здесь будет сгенерирован (написан) код а-ля
//
// longjmp(LABEL ## cor_type.resume_label);
yield();
}
}
// здесь будет сгенерирован (написан) код а-ля
//
// struct courotine_type {
// int a, b
// ucontext context;
// program_counter pc;
// label resume_label; <- это совсем псевдокод, я не очень силен в asm
// ...
// }
coroutine_type cor1 = coroutine();
coroutine_type cor2 = coroutine();
while (!finished)
{
// здесь будет сгенерирован (написан) код а-ля
//
// swapcontext(cor1);
// run_starting_from(cor1.pc);
// LABEL1:
cor1.resume();
// здесь будет сгенерирован (написан) код а-ля
//
// swapcontext(cor2);
// run_starting_from(cor2.pc);
// LABEL2:
cor2.resume();
}
Выше совсем бредоватый псевдокод, но IMHO смысл какой-то такой.
Если же корутина сама вызывает какую-то async операцию, то там может быть и полинг и мутексы и все что угодно, но это уже не связано с корутиной, это часть этой async операции, как в примере вроде:
coroutine_type coroutine()
{
data d = await read_from_tcp(); // внутри read_from_tcp() может быть что угодно
return d;
}
Исправление dissident, :
Под полингом я имел в виду не полинг состояния корутин, а полинг состояния абстракций с которыми они работают.
А если они вовсе не работают ни с какими абстракциями как пример Lua выше а просто делают что-то -> отдают управление по yield -> делают что-то -> отдают управление по yield…
Где в этом примере полинг?
Очевидно, что в такой ситуации корутины используют какую-то lock free структуру для обработки cpu bound задач. В такой ситуации не работал с корутинами, не знаю есть ли в этом случае профит.
Зачем корутинам (стэковым или безстэковым) lock-free структуры, если они выполняются в одном трэде?
В точках создания корутин компилятор должен просто сгенерировать (или программист написать, если корутины реализованы в виде внешней библиотеки) код, который создаст структуру/ucontext для корутины.
В точках yield()/resume() компилятор должен просто сгенерировать (или программист написать) код, который вызовет что-нибудь вроде swapcontext().
AFAIU так как трэд один, никакой полинг/lock-free структуры/мутексы не нужны.
PS я имею ввиду здесь корутины, которые просто делают yield()/resume() без всяких async операций вроде socket::read() «под ними». Т.е., например, тут трэд один и никакой полинг не нужен:
coroutine_type coroutine()
{
coroutine_type cor_type;
int a, b;
while (...)
{
do_smth_a_little_bit();
// здесь будет сгенерирован (написан) код а-ля
//
// longjmp(LABEL ## cor_type.resume_label);
yield();
}
}
// здесь будет сгенерирован (написан) код а-ля
//
// struct courotine_type {
// int a, b
// ucontext context;
// program_counter pc;
// label resume_label; <- это совсем псевдокод, я не очень силен в asm
// ...
// }
coroutine_type cor1 = coroutine();
coroutine_type cor2 = coroutine();
while (!finished)
{
// здесь будет сгенерирован (написан) код а-ля
//
// swapcontext(cor1);
// run_starting_from(cor1.pc);
// LABEL1:
cor1.resume();
// здесь будет сгенерирован (написан) код а-ля
//
// swapcontext(cor2);
// run_starting_from(cor2.pc);
// LABEL2:
cor2.resume();
}
Выше совсем бредоватый псевдокод, но IMHO смысл какой-то такой.
Если же корутина сама вызывает какую-то async операцию, то там может быть и полинг и мутексы и все что угодно, но это уже не связано с корутиной, это часть этой async операции, как в примере вроде:
coroutine_type coroutine()
{
data d = await read_from_tcp(); // внутри read_from_tcp() может быть что угодно
return d;
}
Исправление dissident, :
Под полингом я имел в виду не полинг состояния корутин, а полинг состояния абстракций с которыми они работают.
А если они вовсе не работают ни с какими абстракциями как пример Lua выше а просто делают что-то -> отдают управление по yield -> делают что-то -> отдают управление по yield…
Где в этом примере полинг?
Очевидно, что в такой ситуации корутины используют какую-то lock free структуру для обработки cpu bound задач. В такой ситуации не работал с корутинами, не знаю есть ли в этом случае профит.
Зачем корутинам (стэковым или безстэковым) lock-free структуры, если они выполняются в одном трэде?
В точках создания корутин компилятор должен просто сгенерировать (или программист написать, если корутины реализованы в виде внешней библиотеки) код, который создаст структуру/ucontext для корутины.
В точках yield()/resume() компилятор должен просто сгенерировать (или программист написать) код, который вызовет что-нибудь вроде swapcontext().
AFAIU так как трэд один, никакой полинг/lock-free структуры/мутексы не нужны.
PS я имею ввиду здесь корутины, которые просто делают yield()/resume() без всяких async операций вроде socket::read() «под ними». Т.е., например, тут трэд один и никакой полинг не нужен:
coroutine_type coroutine()
{
coroutine_type cor_type;
int a, b;
while (...)
{
do_smth_a_little_bit();
// здесь будет сгенерирован (написан) код а-ля
//
// swapcontext(cor2);
// longjmp(LABEL ## cor_type.resume_label);
yield();
}
}
// здесь будет сгенерирован (написан) код а-ля
//
// struct courotine_type {
// int a, b
// ucontext context;
// program_counter pc;
// label resume_label; <- это совсем псевдокод, я не очень силен в asm
// ...
// }
coroutine_type cor1 = coroutine();
coroutine_type cor2 = coroutine();
while (!finished)
{
// здесь будет сгенерирован (написан) код а-ля
//
// swapcontext(cor1);
// run_starting_from(cor1.pc);
// LABEL1:
cor1.resume();
// здесь будет сгенерирован (написан) код а-ля
//
// swapcontext(cor2);
// run_starting_from(cor2.pc);
// LABEL2:
cor2.resume();
}
Выше совсем бредоватый псевдокод, но IMHO смысл какой-то такой.
Если же корутина сама вызывает какую-то async операцию, то там может быть и полинг и мутексы и все что угодно, но это уже не связано с корутиной, это часть этой async операции, как в примере вроде:
coroutine_type coroutine()
{
data d = await read_from_tcp(); // внутри read_from_tcp() может быть что угодно
return d;
}
Исправление dissident, :
Под полингом я имел в виду не полинг состояния корутин, а полинг состояния абстракций с которыми они работают.
А если они вовсе не работают ни с какими абстракциями как пример Lua выше а просто делают что-то -> отдают управление по yield -> делают что-то -> отдают управление по yield…
Где в этом примере полинг?
Очевидно, что в такой ситуации корутины используют какую-то lock free структуру для обработки cpu bound задач. В такой ситуации не работал с корутинами, не знаю есть ли в этом случае профит.
Зачем корутинам (стэковым или безстэковым) lock-free структуры, если они выполняются в одном трэде?
В точках создания корутин компилятор должен просто сгенерировать (или программист написать, если корутины реализованы в виде внешней библиотеки) код, который создаст структуру/ucontext для корутины.
В точках yield()/resume() компилятор должен просто сгенерировать (или программист написать) код, который вызовет что-нибудь вроде swapcontext().
AFAIU так как трэд один, никакой полинг/lock-free структуры/мутексы не нужны (я имею ввиду здесь корутины, которые просто делают yield()/resume() без всяких async операций вроде socket::read() «под ними»).
Исправление dissident, :
Очевидно, что в такой ситуации корутины используют какую-то lock free структуру для обработки cpu bound задач. В такой ситуации не работал с корутинами, не знаю есть ли в этом случае профит.
Зачем корутинам (стэковым или безстэековым) lock-free структуры, если они выполняются в одном трэде?
В точках создания корутин компилятор должен просто сгенерировать (или программист написать, если корутины реализованы в виде внешней библиотеки) код, который создаст структуру/ucontext для корутины.
В точках resume()/yield() компилятор должен просто сгенерировать (или программист написать), который вызовет что-нибудь вроде swapcontext().
Трэд один, никакой полинг/lock-free структуры/мутексы не нужны (я имею ввиду здесь корутины, которые просто делают yield()/resume() без всяких async операций вроде socket::read() «под ними»).
Исходная версия dissident, :
Очевидно, что в такой ситуации корутины используют какую-то lock free структуру для обработки cpu bound задач. В такой ситуации не работал с корутинами, не знаю есть ли в этом случае профит.
Зачем корутинам (стэковым или безстэековым) lock-free структуры, если они выполняются в одном трэде?
В точках создания корутин компилятор должен просто сгенерировать (или программист написать) код, который создаст структуру/ucontext для корутины.
В точках resume()/yield() компилятор должен просто сгенерировать (или программист написать), который вызовет что-нибудь вроде swapcontext().
Трэд один, никакой полинг/lock-free структуры/мутексы не нужны (я имею ввиду здесь корутины, которые просто делают yield()/resume() без всяких async операций вроде socket::read() «под ними»).