IO操作是否在绿色线程中运行?

时间:2019-05-09 06:10:17

标签: haskell

Control.Concurrent.Async中的示例为例:

do a1 <- async (getURL url1)
  a2 <- async (getURL url2)
  page1 <- wait a1
  page2 <- wait a2

两个getURL调用是在不同的OS线程上运行还是在不同的绿色线程上运行?

如果我的问题没有意义...说该程序仅在一个OS线程上运行,这些调用是否仍将同时进行?阻塞IO操作会阻塞整个OS线程以及该OS线程上的所有绿色线程,还是仅阻塞一个绿色线程?

3 个答案:

答案 0 :(得分:7)

根据Control.Concurrent.Async

的文档
  

此模块提供了一组用于异步运行IO操作并等待其结果的操作。它是Control.Concurrent提供的基本并发操作的薄层。

Control.Concurrent

  

Haskell线程的调度是在Haskell运行时系统内部完成的,并且不使用任何操作系统提供的线程包。

如果不仔细解释,这最后一点可能会引起误解:尽管Haskell线程的 scheduling (即选择接下来运行的Haskell代码)是在不使用任何操作系统的情况下完成的工具,GHC可以并且确实使用多个OS线程来实际执行选择运行的任何代码,至少在使用线程运行时系统时如此。

答案 1 :(得分:2)

应该都是绿色线程。

如果您的程序是使用单线程RTS编译(或链接)的,则所有绿色线程都在单个OS线程中运行。如果您的程序是使用多线程RTS进行编译(链接)的,则每个CPU核心上(默认情况下)在OS线程上调度了任意数量的绿色线程。

据我所知,在两种情况下,阻塞I / O调用都应该只阻塞一个绿色线程。其他绿色线程应完全不受影响。

答案 2 :(得分:0)

这并不像问题所暗示的那么简单。 Haskell是一种比大多数人都熟悉的功能更强大的编程语言。特别是,从内部角度来看似乎阻塞的IO操作可以通过以下顺序实现:“开始非阻塞IO操作,暂停线程,等待该IO操作在覆盖多个对象的IO管理器中完成” Haskell线程,在IO设备准备就绪后将线程排队以便恢复。”

有关通过标准全局IO管理器提供该功能的API,请参见waitRead#waitWrite#

是否使用绿色线程与该模式无关。可以编写IO操作,以在幕后使用非阻塞IO,并进行适当的多路传输,同时为用户提供阻塞接口。

不幸的是,它也不是那么简单。事实是,操作系统的限制会阻碍您的发展。直到最近(我想也许是昨天发布了5.1内核?),Linux仍没有为非阻塞磁盘操作提供良好的接口。当然,有些东西看起来应该可以工作,但实际上它们并不是很好。因此,磁盘读/写是GHC中的实际阻止操作。 (也不只是在Linux上。GHC并没有很多开发人员支持它,因此即使有其他选择,很多东西都是用与Linux相同的代码编写的。)

但是,这还不如“网络操作隐藏无阻塞,磁盘操作正在阻塞”那么简单。至少可能不是。我实际上并不知道,因为很难在非线程运行时上找到文档。我知道线程运行时实际上维护着一个单独的线程池,用于执行标记为“安全”的FFI调用,这可以防止它们阻止绿色线程的执行。我不知道非线程运行时是否也是如此。

但是对于您的示例,我可以说-假设getURL使用标准网络库(无论如何,这是一个假设函数),它将在后台进行适当的多路复用以实现无阻塞IO。因此,即使没有线程运行时,这些操作也将是真正的并发操作。