TPL - 按顺序运行一系列.net 4.5休息查询

时间:2012-11-08 09:42:03

标签: .net c#-4.0 task-parallel-library

我是一个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任务将是长期运行的任务 - 我需要长时间运行的任务首先启动并首先回调,然后在第一个回调后开始短时间运行GET而不必阻止UI有没有办法做这个可能作为TPL或TPL数据流中的事务,因为在我运行它时,POST确实首先启动,但因为get是一个快速操作,它首先完成并返回第一个我希望它们按顺序发生,就像在同步操作中一样......

所以为了改变代码 - 这会是一个更好的方法吗?

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

1 个答案:

答案 0 :(得分: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);

这种简单的方法将在UI线程上同步执行ProcessCallback。如果您需要使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);

P.S。我离开了Tuple以最小化代码更改,但我建议您使用自定义类型替换它们;它使代码更加清晰。