5

即使在阅读http://krondo.com/?p=1209异步调用是否总是创建/调用新线程之后?我仍然对如何在固有的单线程系统上提供异步调用感到困惑。我将解释我到目前为止的理解并指出我的疑问。

我读到的一个例子是描述一个提供异步处理请求的 TCP 服务器——用户会调用一个方法,例如get(Callback c),稍后会调用回调。现在,我在这里的第一个问题 - 我们已经有两个系统,一个服务器和一个客户端。这不是我的意思,因为事实上我们至少有两个线程——一个在服务器端,一个在客户端。

我读到的另一个例子是 JavaScript,因为这是带有Node.js. 我无法理解的是,也许用 Java 术语思考,是这样的:如果我执行下面的代码(为不正确的,可能是残暴的语法道歉):

function foo(){
    read_file(FIle location, Callback c) //asynchronous call, does not block
    //do many things more here, potentially for hours
}

读取文件的调用执行(某事)并返回,允许我的函数的其余部分执行。由于只有一个线程,即执行我的函数的线程,那么究竟同一个线程(也是唯一一个正在执行我的东西的线程)将如何从磁盘读取字节?

基本上,在我看来,我缺少一些像某种循环调度程序一样的底层机制,它本质上是单线程的,可能会将任务拆分为更小的任务,或者调用会产生线程的多线程组件和读入文件。

提前感谢所有评论并在途中指出我的错误。

更新:感谢所有回复。帮助我解决此问题的其他良好资源如下:

  1. http://www.html5rocks.com/en/tutorials/async/deferred/
  2. http://lostechies.com/johnteague/2012/11/30/node-js-must-know-concepts-asynchrounous/
  3. http://www.interact-sw.co.uk/iangblog/2004/09/23/threadless (.NET)
  4. http://ejohn.org/blog/how-javascript-timers-work/(定时器的内在)
  5. http://www.mobl-lang.org/283/reducing-the-pain-synchronous-asynchronous-programming/
4

2 回答 2

3

The real answer is that it depends on what you mean by "single thread".

There are two approaches to multitasking: cooperative and interrupt-driven. Cooperative, which is what the other StackOverflow item you cited describes, requires that routines explicitly relinquish ownership of the processor so it can do other things. Event-driven systems are often designed this way. The advantage is that it's a lot easier to administer and avoids most of the risks of conflicting access to data since only one chunk of your code is ever executing at any one time. The disadvantage is that, because only one thing is being done at a time, everything has to either be designed to execute fairly quickly or be broken up into chunks that to so (via explicit pauses like a yield() call), or the system will appear to freeze until that event has been fully processed.

The other approach -- threads or processes -- actively takes the processor away from running chunks of code, pausing them while something else is done. This is much more complicated to implement, and requires more care in coding since you now have the risk of simultaneous access to shared data structures, but is much more powerful and -- done right -- much more robust and responsive.

Yes, there is indeed a scheduler involved in either case. In the former version the scheduler is just spinning until an event arrives (delivered from the operating system and/or runtime environment, which is implicitly another thread or process) and dispatches that event before handling the next to arrive.

于 2014-01-21T16:30:18.833 回答
0

我在 JavaScript 中的想法是有一个保存事件的队列。在旧的 Java 生产者/消费者的说法中,有一个消费者线程从这个队列中拉出东西并执行每个注册的函数来接收当前事件。异步调用(AJAX 请求完成)、超时或鼠标事件等事件一旦发生就会被推送到队列中。单个“消费者”线程将它们从队列中拉出并定位任何感兴趣的函数然后执行它们,它无法到达下一个事件,直到它完成调用在当前事件上注册的所有函数。因此,如果您有一个永远不会完成的处理程序,则队列只会填满 - 它被称为“阻塞”。

系统有多个线程(它至少有一个生产者和一个消费者),因为某些东西会生成要进入队列的事件,但作为事件处理程序的作者,您需要注意事件是在单个线程中处理的,如果你进入一个紧密的循环,你将锁定唯一的消费者线程并使系统无响应。

所以在你的例子中:

 function foo(){
    read_file(location, function(fileContents) {
        // called with the fileContents when file is read
    }     
    //do many things more here, potentially for hours
 }

如果您按照您的评论执行并可能执行数小时 - 即使文件已被读取,处理 fileContents 的回调也不会触发数小时。一旦你点击了 foo() 的最后一个},消费者线程就完成了这个事件,并且可以处理下一个事件,它将使用文件内容执行注册的回调。

高温高压

于 2014-01-21T16:52:49.150 回答