如何在运行其他任务之前完成任务

时间:2014-09-11 21:07:00

标签: c# asp.net-web-api task-parallel-library async-await

我正在使用Microsoft Web API 2.2客户端从API端点请求数据。获取数据后,我运行了多个DoSomeWork。我想确保在运行DoSomeWork函数之前先加载数据。

根据下面的代码,我期待以下输出。

  

“开始GetSomething”   “用GetSomething完成”   “开始工作#1”   “开始工作#2”

但我得到以下内容 “开始GetSomething” “开始工作#1” “用GetSomething完成” “开始工作#2”

    static void Main()
    {
        try
        {
            Task getSomethingTask = Task.Factory.StartNew(()=>GetSomething());
            getSomethingTask.Wait();
            Task[] tasks = new Task[2] {
                 Task.Facotry.StartNew(()=>DoSomeWork(1)),
                 Task.Facotry.StartNew(()=>DoSomeWork(2))
            };
            Task.WaitAll(tasks);
        }
        catch(Exception ex)
        {
           throw ex;
        }
    }
    static async Task GetSomething()
    {
        Console.WriteLine("Starting GetSomething");
        try
        {
            HttpClient client = new HttpClient();
            client.BaseAddress = new Uri(SOME_URL);
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            HttpResponseMessage response = await client.GetAsync("api/v1/somethings");
            somethingList = await response.Content.ReadAsAsync<SomeObject>();
        }
        catch (Exception)
        {

            throw;
        }
        Console.WriteLine("Done with GetSomething");
    }
    static async Task DoSomeWork(int workNumber)
    {
       Console.Writeline("Start work#" + workNumber);
    }

3 个答案:

答案 0 :(得分:1)

在进行异步编程(即I / O绑定)时,您要避免StartNewWaitWaitAll。相反,请将asyncawait用于几乎所有逻辑。

由于这是一个控制台应用程序,因此您需要一个Wait,以便主线程不会退出。这应该是整个应用中唯一的Wait

static void Main()
{
  MainAsync().Wait();
}

static async Task MainAsync()
{
  await GetSomethingAsync();
  await Task.WhenAll(DoSomeWorkAsync(1), DoSomeWorkAsync(2));
}

static async Task GetSomethingAsync()
{
  Console.WriteLine("Starting GetSomething");
  HttpClient client = new HttpClient();
  ...
  HttpResponseMessage response = await client.GetAsync("api/v1/somethings");
  somethingList = await response.Content.ReadAsAsync<SomeObject>();
  Console.WriteLine("Done with GetSomething");
}

static async Task DoSomeWorkAsync(int workNumber)
{
  Console.Writeline("Start work#" + workNumber);
}

您可能会发现我的async intro有帮助。

答案 1 :(得分:0)

我相信getSomethingTask会立即完成,因为您await GetSomething() {/ 1}}。

试试这个:

Task getSomethingTask = Task.Factory.StartNew(async () => await GetSomething());

或简单地说:

GetSomething().Wait();

虽然我不认为你通过创建一个新线程并立即在主线程上等待结果来获得任何东西。

答案 2 :(得分:0)

当您从某个线程调用await时,您将控制权交还给其父线程。

在这种情况下,这是您的违规行:

HttpResponseMessage response = await client.GetAsync("api/v1/somethings");

一旦这样做,你的GetSomething线程就会将控制权交还给Main()线程,这就是你看到DoSomeWork任务正在执行的原因。

如果你摆脱了await中的GetSomething次呼叫,而是用同步呼叫替换它们,你就会得到你想要的行为。

有关详细信息,请参阅此处的Microsoft异步编程指南(特别是步骤#6,其中讨论了await):http://msdn.microsoft.com/async