我读了这篇维基百科text切片:
由于协同多任务系统依赖于每个进程定期放弃时间到系统上的其他进程,一个设计不佳的程序可能会占用自身的所有CPU时间或导致整个系统挂起
出于好奇,那个人如何放弃那个时间?这是某种操作系统调用吗?让我们考虑一些非抢占式的情况,比如光纤或协议多任务执行的协议IO。他们如何放弃那段时间?
拿这个NodeJS示例:
var fs = require('fs');
fs.readFile('/path/to/file', function(err, data) {});
对我来说很明显,这个过程在等待数据时什么都不做,但在这种情况下V8如何为其他进程腾出时间?
让我们假设Linux / Windows是我们的操作系统。
编辑:我发现谷歌是如何用他们的V8做的。
在Windows上他们基本上没有睡觉时间:
void Thread::YieldCPU() {
Sleep(0);
}
在Linux上,他们拨打了OS电话:
void Thread::YieldCPU() {
sched_yield();
}
sched.h
的。
答案 0 :(得分:4)
是的,每个程序都参与操作系统的调度决策,因此您必须调用一个特定的系统调用来告诉内核重新收回。通常这被称为 yield()。如果你想象保证在常规,短时间间隔甚至根本不需要调用特定代码行是多么困难,你就会明白为什么协作式多任务处理是次优解决方案。
在您的示例中,如果操作系统调度程序是抢占式操作系统,则javascript引擎本身会被其中断。如果它是合作的,那么不,引擎没有完成工作,也没有任何其他过程。因此,此类系统通常不适用于实时(甚至严重)工作负载。
答案 1 :(得分:2)
这种操作系统的一个例子是NetWare。在该系统中,有必要调用一个特定的函数(我认为它被称为ThreadSwitch或ThreadSwitchWithDelay)。并且总是猜测它需要多久。在产品的每个CPU密集型循环中,必须定期调用其中一个函数。
但在该系统中,其他调用将导致允许其他线程运行。特别是(与问题密切相关)是I / O调用导致操作系统有机会运行其他线程。基本上任何控制操作系统的系统调用都足以允许其他线程运行(互斥/信号量调用是重要的)。
答案 2 :(得分:0)
作为一般规则,合作多任务涉及表明他们正在等待的功能,而不是进入自旋循环(等待时他们处理的地方)他们自己暂停。
在这种情况下,ReadFile后面的处理将处理等待数据以及可挂起的相关信号。在你自己的代码中,无论它是什么,你应该暂停处理,如果你正在等待一个长时间运行的进程,而不是旋转。但是,在许多情况下,挂起过程会自动处理,因为挂起活动是内置的。如果你故意强制进行长期旋转,那么你将会挂起系统。
另一种选择(来自该维基)是先发制人的多任务处理,在一定时间后,该过程被强制排除,无论它在做什么。这意味着无论你做什么,它都无法永远运行,因为系统进程会强制它。但是,由于未定义断点,因此效率较低。