帮我约的理由F#主题 [英] help me reason about F# threads

查看:103
本文介绍了帮我约的理由F#主题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在玩玩而已的一些F#(通过MonoDevelop的),我写了一个程序,其中列出目录中的文件有一个线程:

In goofing around with some F# (via MonoDevelop), I have written a routine which lists files in a directory with one thread:

let rec loop (path:string) = 
  Array.append
    (
        path |> Directory.GetFiles
    )
    (
        path 
        |> Directory.GetDirectories
        |> Array.map loop
        |> Array.concat
    )

然后异步版本吧:

And then an asynchronous version of it:

let rec loopPar (path:string) = 
  Array.append
    ( 
        path |> Directory.GetFiles
    )
    ( 
        let paths = path |> Directory.GetDirectories
        if paths <> [||] then
            [| for p in paths -> async { return (loopPar p) } |]
            |> Async.Parallel
            |> Async.RunSynchronously 
            |> Array.concat
        else 
            [||]
    ) 

在小目录,异步版本工作正常。上更大的目录(例如,成千上万的目录和文件),异步版本似乎挂起。我缺少什么?

On small directories, the asynchronous version works fine. On bigger directories (e.g. many thousands of directories and files), the asynchronous version seems to hang. What am I missing?

我知道,创造数千个线程是永远不会是最有效的解决方案 - 我只有8个CPU - 但我困惑的是对于较大的目录异步函数只是甚至没有一个半小时后仍未响应( )。它没有明显的失败,虽然,这令我​​感到困惑。是否有被耗尽的线程池?

I know that creating thousands of threads is never going to be the most efficient solution -- I only have 8 CPUs -- but I am baffled that for larger directories the asynchronous function just doesn't respond (even after a half hour). It doesn't visibly fail, though, which baffles me. Is there a thread pool which is exhausted?

如何将这些线程的实际工作?

How do these threads actually work?

编辑:

根据本文

单> = 2.8.x之前有一个新的线程池的多,更难死锁。如果你得到一个线程池的僵局有可能你的程序试图陷入僵局。

Mono >=2.8.x has a new threadpool that is much, much harder to deadlock. If you get a threadpool deadlock chances are that your program is trying to be deadlocked.

:D

推荐答案

是的,很有可能你是压倒这是粉磨系统的性能提升到一个停止Mono的线程池。

Yes, most likely you are overwhelming the Mono thread pool which is grinding your system's performance to a halt.

如果您还记得这样一件事,那就是线程是昂贵。每个线程都需要自己的堆栈(大小兆字节)和CPU时间(需要上下文切换)片。正因为如此,它是很少旋转起来自己的线程短暂的任务是一个好主意。这就是为什么.NET有一个线程池。

If you remember one thing from this, it is that threads are expensive. Each thread needs its own stack (megabytes in size) and slice of CPU time (requiring context switching). Because of this, it is rarely a good idea to spin up your own thread for short lived tasks. That is why .NET has a ThreadPool.

一个线程池技术是一种短任务的线程的现有集合,它是F#用户对于它的异步工作流程。每当你运行一个F#异步操作,它只是代表了行动,线程池。

A ThreadPool is an existing collection of threads for short tasks, and it is what F# users for its Async workflows. Whenever you do run an F# Async operation, it simply delegates the action to the thread pool.

问题是,当你在F#产卵数千异步操作的所有一次会发生什么?根据需要一个天真的实施将简单地产卵多线程。但是,如果您需要1000线程意味着你需要的堆栈空间1000×4MB。即使你有所有堆栈足够的内存,您的CPU将不停地在不同的线程之间的切换。 (和分页进出内存的本地栈)。

The problem is, what happens when you spawn thousands of asynchronous actions in F# all at once? A naive implementation would simply spawn as many threads as needed. However, if you need 1,000 threads that means you need 1,000 x 4MB of stack space. Even if you had enough memory for all the stacks, your CPU would constantly be switching between the different threads. (And paging the local stacks in and out of memory.)

IIRC,直到有一些空闲的线程来执行的操作在Windows .NET实现足够明智,不产卵一吨的线程,只是排队的工作了。换句话说,它会继续增加线程,直到它有一个固定数量,只是使用的那些。但是,我不知道Mono的线程池是如何实现的。

IIRC, the Windows .NET implementation was smart enough not to spawn a ton of threads and simply queue the work up until there were some spare threads to perform the actions. In other words, it would keep adding threads until it had a fixed number and just use those. However, I don't know how Mono's thread pool is implemented.

TL;博士:这是按预期工作

tl;dr: This is working as expected.

这篇关于帮我约的理由F#主题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆