Task.WaitAll的线程局部对象

时间:2011-10-20 20:46:34

标签: .net f# parallel-processing task-parallel-library

我有少量任务,我想使用Task.WaitAll并行运行它们。这就是我现在所拥有的:

type System.Threading.Tasks.Task with
  static member WaitAll(ts) =
    Task.WaitAll [| for t in ts -> t :> Task |]

let processf p fs =
  let rand = Random ()
  let ts = fs |> Array.map (fun f -> Task.Factory.StartNew(fun () -> p(f, rand)))
  Task.WaitAll(ts)
  ts |> Array.map (fun t -> t.Result)

问题是Random不是线程安全的(Random类仅用于说明目的)。如何为每个线程创建一个对象,而不是为每个Task创建一个对象,这是浪费?

修改

像Brian和Daniel的建议一样使用ThreadStatic是一种很好的方法,特别是对于工厂类。但是,我更喜欢Reed和Tomas建议的ThreadLocal,因为它看起来更简单。我同意使用主人Random有点过于复杂。以下是我保留以供将来参考的混合解决方案:

let processf p fs =
  use localRand = new ThreadLocal<_>(
                       fun() -> Random(Thread.CurrentThread.ManagedThreadId))
  let ts = fs |> Array.map (fun f -> 
                          Task.Factory.StartNew(fun () -> p(f, localRand.Value)))
  Task.WaitAll(ts)
  ts |> Array.map (fun t -> t.Result)

5 个答案:

答案 0 :(得分:3)

您可以将特定于线程的状态放在工厂类中,并将其标记为ThreadStatic

type PerThread =

  [<ThreadStatic; DefaultValue>]
  static val mutable private random : Random

  static member Random = 
    match PerThread.random with
    | null -> PerThread.random <- Random(Thread.CurrentThread.ManagedThreadId)
    | _ -> ()
    PerThread.random

然后你可以这样做:

let process p fs =
  let ts = fs |> Array.map (fun f -> 
    Task.Factory.StartNew(fun () -> p(f, PerThread.Random)))
  Task.WaitAll(ts)
  ts |> Array.map (fun (t: Task) -> t.Result)

答案 1 :(得分:2)

您可以使用ThreadLocal<'T> class存储Random实例。这将提供线程局部随机值,可在完成任务后进行处理。

答案 2 :(得分:2)

recent F# question here on StackOverflow实现了您正在寻找的内容。

使用线程局部(线程静态)存储是可行的方法,但是您应该小心 - 当所有线程同时启动时,它们也有可能获得相同的初始种子。为了解决这个问题,上面的实现使用了一个由锁定保护的 master Random,用于为各个线程生成种子。

答案 3 :(得分:1)

您可以将'rand'声明为ThreadStatic。或者,TPL中有一些允许TLS的API;我不知道所有这些,但请参阅例如here,可能会跳出点找其他人。 (希望其他人会发布更多细节或改进这个答案。)

答案 4 :(得分:0)

我认为您的活动不需要Thread Local。您可以使用当前线程ID在每个任务中创建新的Random对象。 例如:

Task.Factory.StartNew(fun () -> p(f, new Random(Thread.CurrentThread.ManagedThreadId))))

我认为这更简单易懂,而不是跟踪Thread局部变量。