0

私は少しTPL初心者です。このライブラリが進むべき道かどうかはわかりませんが、一連の非同期タスクを順番に実行したいのですが、UIをブロックせずに、順番に実行し、開始された順序でコールバックします-それらを実行するのと少し似ています同期的に。したがって、事実上、タスクが終了し、HttpResponseMessage ..がある場合にのみコールバックし、次のタスクを開始します。

したがって、動作は次のようになります

長時間実行タスク1を実行して、UIで何かを実行できるようにします。次に、完全コールバック時に次の長時間実行タスクを実行して、UIを更新します。UIを更新できるように、コールバックが完了したら、より短いタスクを実行します

スケジューラーが使用されている例を見てきましたが、とにかくここに私のコードがあります

private void RunSequentially()
{
        var lcts = new LimitedConcurrencyLevelTaskScheduler(1);
        var factory = new TaskFactory(lcts);
        string username = "user";
        string password = "password";
        var handler = new HttpClientHandler
            {
               Credentials = new NetworkCredential(username, password), PreAuthenticate = true 
            };
        var client = new HttpClient(handler);

        List<Tuple<string,string,string>> taskTuples = new List<Tuple<string, string, string>>();
        taskTuples.Add(new Tuple<string, string, string>("POST", "http://longrunning", XDocument.Load(@"./somefile.xml").ToString()));
        taskTuples.Add(new Tuple<string, string, string>("GET", "http://getItem", null));

        factory.StartNew(
            () =>
                {
                    foreach(var tuple in taskTuples)
                    {
                        ProcessSequentially(tuple,ProcessCallback, client);
                    }
                });
    }

そしてProcessSequentiallyメソッド

private async void ProcessSequentially(Tuple<string, string, string> tuple, Action<string> callback, HttpClient client)
    {
        HttpResponseMessage message = null;
        if (tuple.Item1 == "POST")
        {
            message = await
                client.PostAsync(
                    tuple.Item2,
                    new StringContent(tuple.Item3));
        }
        else
        {
            message = await
                client.GetAsync(
                    tuple.Item2);
        }

        callback(message.ReasonPhrase);


    }

ここで、postタスクが長時間実行されるタスクであると仮定します-最初に起動して最初にコールバックし、次に、WaitAllを介してUIをブロックすることなく、最初のタスクがコールバックした後に短時間実行するGETを開始する必要がありますこれをTPLまたはTPLデータフローのトランザクションとして実行する方法はありますか?これを実行すると、POSTが最初に開始されますが、getは高速操作であるため、最初に完了して最初に戻ります。それらは同期操作のように順番に発生します。

それで、コードを変更するために-これは行くためのより良い方法でしょうか?

foreach (var tuple in taskTuples)
        {
            factory.StartNew(
            () =>
            {
                this.ProcessSequentially(tuple,client);
            }).ContinueWith(this.FinishSequentialTask);
        }
4

1 に答える 1

1

シーケンシャルな非同期コードが必要です。awaitこれに最適です:

private async Task RunSequentially()
{
  string username = "user";
  string password = "password";
  var handler = new HttpClientHandler
  {
    Credentials = new NetworkCredential(username, password), PreAuthenticate = true 
  };
  var client = new HttpClient(handler);

  List<Tuple<string,string,string>> taskTuples = new List<Tuple<string, string, string>>();
  taskTuples.Add(new Tuple<string, string, string>("POST", "http://longrunning", XDocument.Load(@"./somefile.xml").ToString()));
  taskTuples.Add(new Tuple<string, string, string>("GET", "http://getItem", null));
  foreach (var tuple in taskTuples)
  {
    await Process(tuple, ProcessCallback, client);
  }
}

private async Task Process(Tuple<string, string, string> tuple, Action<string> callback, HttpClient client)
{
  HttpResponseMessage message = null;
  if (tuple.Item1 == "POST")
  {
    message = await
        client.PostAsync(
            tuple.Item2,
            new StringContent(tuple.Item3));
  }
  else
  {
    message = await
        client.GetAsync(
            tuple.Item2);
  }

  callback(message.ReasonPhrase);
}

private void ProcessCallback(string reason);

この単純なアプローチはProcessCallback、UIスレッドで同期的に実行されます。非同期にする必要がある場合は、次のようProcessCallbackにすることができます。

private async Task Process(Tuple<string, string, string> tuple, Func<string, Task> callback, HttpClient client)
{
  HttpResponseMessage message = null;
  if (tuple.Item1 == "POST")
  {
    message = await
        client.PostAsync(
            tuple.Item2,
            new StringContent(tuple.Item3));
  }
  else
  {
    message = await
        client.GetAsync(
            tuple.Item2);
  }

  await callback(message.ReasonPhrase);
}

private async Task ProcessCallback(string reason);

PSTupleコードの変更を最小限に抑えるために、sを残しましたが、カスタムタイプに置き換えることをお勧めします。コードがより明確になります。

于 2012-11-08T14:59:35.203 に答える