4

F# を使用して並列プログラミングを行っています。固定数の要素、たとえば 2 つの要素 a1、a2 および関数 f を使用すると、次のように実行できます。

let t1 = Task.Factory.StartNew(fun () -> f a1)
let t2 = Task.Factory.StartNew(fun () -> f a2)
Task.WaitAll(t1, t2)
t1.Result, t2.Result

要素のリストでどうやって同じことができるのだろうか:

let ts = List.map (fun a -> Task.Factory.StartNew(fun () -> f a))
Task.WaitAll(ts)
List.map (fun (t: Task<_>) -> t.Result) ts

Visual Studio は、Task.WaitAll が Task< T > リストをパラメーターとして受け入れることができなかったことを検出します。Task.WaitAll は Task [] を引数として持つことができますが、次の計算のために Result を取得する必要があるため意味がありません。

4

3 に答える 3

8

Robert が説明しているように、 を呼び出したい場合はWaitAll、要素シーケンスを基本型にキャストしてTaskから、それを配列に変換する必要があります。拡張メンバーを定義Taskして、tas をより簡単にすることができます。

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

私は配列内包表記とキャストを代わりに使用しています。これは、型指定されていないSeq.castためです。そのため、F# は拡張メソッドのより適切な型を推測します。Seq.castIEnumerable

別のオプションはWaitAll、まったく呼び出さないことです。呼び出さないとResult、タスクが完了するまでプロパティがブロックされます。これは、とにかくスレッドをブロックすることを意味します (ブロックの数が少し多いかもしれませんが、パフォーマンスに大きな影響を与えるかどうかはわかりません)。を使用List.mapしてすべての結果を収集する場合、動作はほぼ同じになります。

于 2011-02-25T13:53:18.197 に答える
4

これは残念なデザインです。Task.WaitAll は、c# の params キーワードを使用して、複数の引数を指定し、それらをメソッド内の配列にすることができます。また、C# の暗黙的なキャストを使用して、 を与えることができますTask<T>。F# では、明示的にキャストして配列に変換することで、これを自分で行う必要があります。

let ts = [| 
     Task.Factory.StartNew(fun () -> 1)
     Task.Factory.StartNew(fun () -> 2)
     |]
Task.WaitAll(ts |> Seq.cast<Task> |> Array.ofSeq)

これで、 から結果を取得できますts

于 2011-02-25T12:57:15.450 に答える
1

配列にもマップがあるため、タスクを配列に入れられない理由はありません。

または、waitall のためだけに配列に変換することもできます...

于 2011-02-25T11:54:42.840 に答える