3

戻り値の型が異なる、または戻り値の型がまったくないタスクをチェーンすることは可能ですか? たとえば、擬似コードでは次のようになります。

Task<double>.ContinueWith(Task<string>).ContinueWith(Task<String>).ContinueWith(Task)

または、実際のコード例もここにあります:

private double SumRootN(int root)
{
    double result = 0;
    for (int i = 1; i < 10000000; i++)
    {
        result += Math.Exp(Math.Log(i) / root);
    }
    return result;
}

private void taskSequentialContinuationButton_Click(object sender, RoutedEventArgs e)
{
    Task<double> task = null;

    this.statusText.Text = "";
    this.watch = Stopwatch.StartNew();
    for (int i = 2; i < 20; i++)
    {
        int j = i;
        if (task == null)
        {
            task = Task<double>.Factory.StartNew(() => { return SumRootN(j); });
        }
        else
        {
            task = task.ContinueWith((t) => { return SumRootN(j); });
        }

        task = task.ContinueWith((t) => 
        { // I don't want to return anything from this task but I have to, to get it to compile
            this.statusText.Text += String.Format("root {0} : {1}\n", j, t.Result);
            return t.Result;
        }, TaskScheduler.FromCurrentSynchronizationContext());
    }

    task.ContinueWith((t) => 
        { // I also don't want to return anything here but I don't seem to have to here even though intellisense expects a Task<double>??
            this.statusText.Text += String.Format("{0}ms elapsed\n", watch.ElapsedMilliseconds);
        }, TaskScheduler.FromCurrentSynchronizationContext());
}

チェーンの奇妙さについては、インライン コメントを参照してください。

4

2 に答える 2

4

戻り値の型が異なる sを連鎖させたい場合はTask、それぞれを別の変数に入れるだけです。

Task<Type1> task1 = Task.Factory.StartNew(() => Compute1());
Task<Type2> task2 = task1.ContinueWith(_ => Compute2());
Task<Type3> task3 = task2.ContinueWith(_ => Compute3());

ループ内で何かを計算し、各反復後に UI スレッドについて報告する特定のケースでは、次のように実行できます。

var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();

Task.Factory.StartNew(() =>
{
    for (int i = 2; i < 20; i++)
    {
        // perform computation

        Task.Factory.StartNew(() =>
        {
            // report result
        }, CancellationToken.None, TaskCreationOptions.None, uiScheduler);
    }
});
于 2012-06-24T20:28:56.653 に答える
0

単一のtask変数を再利用するため、コードが複雑になります。いくつかのタスクを起動して、それらが完了するのを待ちたいようです。このようなものが動作するはずです:

SynchronizationContext context = SynchronizationContext.Current;

Task[] tasks = Enumerable.Range(2, 19)
    .Select(d => Task<double>.Factory.StartNew(() => SumRootN(d))
        .ContinueWith(t => {
            this.statusText.Text += string.Format("root {0} : {1}\n", d, t.Result);
        }))
    .ToArray();

Task.Factory.StartNew(() => {
    Task.WaitForAll(tasks);
    string msg = string.Format("{0}ms elapsed\n", watch.ElapsedMilliseconds);
    context.Post(_ => { this.statusText.Text += msg; }, null);
});

編集:一連のタスクを作成したい場合、これはうまくいくかもしれません:

Task first = new Task(() => { });
Task outer = Enumerable.Range(2, 19)
    .Aggregate(first, (task, d) => {
        Task inner = new Task<double>(() => SumRootN(d))
            .ContinueWith(rt => {
                this.statusText.Text += String.Format("root {0} : {1}\n", d, rt.Result);
            });
        return task.ContinueWith(inner);
    });

outer.ContinueWith(t => {
    this.statusText.Text += String.Format("{0}ms elapsed\n", watch.ElapsedMilliseconds);
});

first.Start();
于 2012-06-24T18:20:49.797 に答える