使用单个线程进行异步处理

即使阅读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 } 

对read文件的调用执行(sth)并返回,允许我的其余函数执行。 既然只有一个线程,即执行我的函数的线程,那么同一个线程(执行我的东西的唯一一个线程)将如何从磁盘读取字节?

基本上,在我看来,我缺少一些基本机制,就像某种类型的循环调度程序,它本身就是单线程的,可能会将任务拆分为较小的或调用multithreading组件,这些组件会产生一个线程,读取文件。

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

更新 :感谢所有回复。 帮助我解决这个问题的更多好消息来源是:

  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/

真正的答案是它取决于你所说的“单线程”。

多任务处理有两种方法:协作和中断驱动。 Cooperative,这是你引用的其他StackOverflow项目所要求的,它要求例程明确放弃处理器的所有权,以便它可以做其他事情。 事件驱动系统通常以这种方式设计。 优点是管理起来要容易得多,并且避免了大部分数据冲突访问的风险,因为任何时候只有一大块代码在执行。 缺点是,因为一次只做一件事,所以一切都必须设计得相当快,或者被分解成块(通过像yield()调用这样的显式暂停),或系统在该事件完全处理之前,它似乎会冻结。

另一种方法 – 线程或进程 – 主动使处理器远离运行代码块,在完成其他操作时暂停它们。 这实现起来要复杂得多,并且需要更加谨慎的编码,因为您现在可能同时访问共享数据结构,但function更强大 – 做得更好 – 更加强大和响应更快。

是的,在任何一种情况下都确实涉及调度程序。 在以前的版本中,调度程序只是旋转直到事件到达(从操作系统和/或运行时环境传递,这是隐式的另一个线程或进程)并在处理下一个到达之前调度该事件。

我在JavaScript中的想法是有一个包含事件的Queue。 在旧的Java生产者/消费者的说法中,有一个消费者线程从这个队列中拉出东西并执行注册接收当前事件的每个函数。 异步调用(AJAX请求完成),超时或鼠标事件等事件一旦发生就会被推送到队列。 单个“消费者”线程将它们从队列中拉出并找到任何感兴趣的函数,然后执行它们,在它完成调用当前注册的所有函数之前,它无法进入下一个事件。 因此,如果你有一个永远不会完成的处理程序,那么Queue就会填满 – 据说它被“阻止”了。

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

所以在你的例子中:

  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()的最后一个消息线程就完成了这个事件,并且可以处理下一个事件,它将使用文件内容执行注册的回调。

HTH