Как erlang реализует упреждающее планирование с одним потоком ОС?
Я хочу знать, как виртуальная машина Эрланга вытесняет работающий код и контекстирует стек. Как это можно сделать на таком языке, как с?
1 ответ
Хитрость заключается в том, что среда выполнения Erlang имеет контроль над ВМ, поэтому она может - полностью в пользовательском пространстве - отслеживать, сколько инструкций ВМ уже выполнено (или, что еще лучше, оценить или представить фактические физические вычисления, требуемые для этих инструкций). - иначе говоря, "сокращение" на языке Erlang VM) и - если это число превышает некоторый порог - немедленно поменяйте местами указатели / структуры / что угодно процесса и возобновите цикл выполнения.
Подумайте об этом как-то так (вроде псевдо-C, который на самом деле может быть, а может и не быть C, но я бы не знал, потому что я не программист на C, но вы спросили, как бы вы поступили в C так что я постараюсь изо всех сил)
void proc_execute(Proc* proc)
{
/* I don't recall if Erlang's VM supports different
reduction limits for different processes, but if it
did, it'd be a rather intuitive way to define process
priorities, i.e. making sure higher-priority processes
get more reductions to spend */
int rds = proc->max_reductions;
for (; rds > 0; rds--) {
/* Different virtual instructions might execute different numbers of
physical instructions, so vm_execute_next_instruction will return
however many reductions are left after executing that virtual
instruction. */
rds = vm_execute_next_instruction(proc, rds);
if (proc->exited) break;
}
}
void vm_loop(Scheduler* sched)
{
Proc *proc;
for (;;) {
proc = sched_next_in_queue(sched);
/* we'll assume that the proc will be null if the
scheduler doesn't have any processes left in its
list */
if (!proc) break;
proc_execute(proc);
}
}
Proc* sched_next_in_queue(Scheduler* sched)
{
if (!sched->current_proc->exited) {
/* If the process hasn't exited yet, readd it to the
end of the queue so we can resume running it
later */
shift(sched->queue, sched->current_proc);
}
sched->current_proc = pop(sched->queue);
return sched->current_proc;
}
Это, очевидно, довольно упрощенно (особенно исключая / исключая много важных вещей, таких как, как реализованы инструкции VM и как сообщения передаются), но, надеюсь, это иллюстрирует, как (если я правильно понимаю, по крайней мере) упреждающий планировщик и модель процесса Эрланга работает на базовом уровне.
Весь код Erlang скомпилируется в код операции виртуальной машины Erlang. Виртуальная машина Erlang выполняет код операции Erlang потоками ОС, которые создаются при запуске виртуальной машины Erlang.
Код Erlang работает на виртуальных процессорах, которые управляются виртуальной машиной Erlang. И виртуальная машина Эрланга считает IO прерыванием виртуальных процессоров. Таким образом, виртуальная машина Эрланга реализует машину и планировщик как ОС. Из-за кода операции и неблокирующего ввода-вывода, мы можем реализовать прерывания в виртуальной машине Эрланга, используя язык C.