原因是当GHCi中的函数退出时,它产生的线程不会自动终止,即使通过代码重新加载仍然存在.重新启动GHCi解决了这个问题,但是由于我的应用程序需要一段时间才能加载,所以如果有可能(甚至是黑客)的解决方法,这将是巨大的.
解决方法
此外,您无法可靠地猜测使用forkIO产生的线程属于您的GHCi会话(所有评估通常在forkIO中进行沙盒),底层的yesod应用程序或线程RTS(至少有一个对forkIO的调用),这基本上确保了所有事件管理器都关闭).目前,这并不是太糟糕了,因为GHCi运行在主线程中,如果关闭,IO管理器将重新启动,但在将来的版本中可能会发生更改.
那么为什么线程甚至在终止时收集? hs_exit()
.本质上,它调用ioManagerDie()(kill all event managers)和exitScheduler(..)(参见scheduler,基本上是kills all threads.这些函数都没有一个适当的FFI包装器.
在调用hs_exit()时,Haskell世界的主要功能已经完成.因为这些函数中没有一个在GHC *模块中具有适当的等效项,所以不能直接在Haskell中调用它们,因此不能在GHCi中调用它们,因为没有适当的:#命令.
所以总而言之,你不能.如果要添加一个命令来重新启动GHCi中的调度程序,这将很容易.但是考虑到调度程序在hs_init()中启动并在RTS model中的hs_exit()中停止,我怀疑这将是一个容易的扩展.
根据你想做什么,你可以作弊.您可以编写自己的forkIOMem,它将ThreadId存储在全局MVar中,并替换源中的所有forkIO.这可能非常麻烦,特别是如果您正在使用图书馆,因为您需要确保将forkIO替换到任何地方.
当然,您可以使用基础包,但是这可能是疯狂的(尽管如此),更改forkIO,并将killAllforkIO添加到Control.Concurrent. (我已经说过这可能是疯狂的吧?)