如何正确地等待任务中的任务?

时间:2018-10-28 05:42:29

标签: c# task

我正在使用Flurl发出请求。目前,我有以下代码,并且一切正常:

public class Request()
{
    public async Task<Bitmap> GetImage(string url)
    {
        using (var client = new Url(url)
        {
            var content = await client.GetStringAsync();
            //return as image
        }
    }
}

在主UI线程上,我这样做:

public async void GetImages()
{
    for (int i = 0; i < someCounter; i++)
    {
        var img = await myRequest.GetImage(url);
        Thread.Sleep(100);
    }
}

以上方法有效,但是UI线程休眠了一段时间,我想在一个任务中完成以上操作。所以我做到了:

public async void GetImages()
{
    await Task.Run(async () => 
    {
        for (int i = 0; i < someCounter; i++)
        {
            var img = await myRequest.GetImage(url);
            Thread.Sleep(100);
        }
    });
}

但是,使用上述方法,代码在await client.GetStringAsync();处停止。也不例外,代码要么在那里停止执行,要么等待一些东西。

是我要尝试纠正的问题,还是有更好的方法?如果正确,为什么内部等待永远不会完成?

2 个答案:

答案 0 :(得分:1)

不要使用Thread.Sleep(100);,它不会await,它不会把线程退回,它只会坐在那里什么都不做,并按住您的 UI

如果有的话,您应该使用Task.Delay,它将与async配合使用,不会阻塞 UI 线程,并且可以在 CallBack < / em>。

此外,您应该通过返回async(并且仅使用await),使async Task async void模式像病毒一样传播到启动该事件的事件

public async Task GetImages()
{
    for (int i = 0; i < someCounter; i++)
    {
        var img = await myRequest.GetImage(url);
        // for your small wait.
        await Task.Delay(100);
    }
}

如果您担心所有状态机,则在某些情况下,您只能返回Task而不返回await

此外,在您的基础库中,没有任何内容可以返回到捕获的上下文,因此适合调用ConfigureAwait(false);,这会给您带来一点效率

var content = await client.GetStringAsync()
                          .ConfigureAwait(false);

答案 1 :(得分:1)

如果您想使用睡眠,则可能应该使用Task.Delaypost将为您提供有关何时使用Thread.Sleep和何时使用Task.Delay的更好的见解。

第二,在代码中,应执行以下操作,而不是等待和睡觉:

public async void GetImages()
{
   var tasks = new List<Task>();
   for (int i = 0; i < someCounter; i++)
   {
      tasks.Add(myRequest.GetImage(url));
   }
   await Task.WhenAll(tasks).ConfigureAwait(false);
}

for循环结束时注意WhenAll调用,这将创建一个任务,该任务将在所有提供的任务完成时完成。

然后,ConfigureAwait(false)告诉等待中您不需要在当前上下文上恢复(在这种情况下,“在当前上下文上”意味着“在UI线程上”)

第三,在您对该网址的调用中,将其更改为Task.Run

public class Request()
{
    public async Task<Bitmap> GetImage(string url)
    {
        using (var client = new Url(url)
        {
            //return as image
            var content = await Task.Run(() => client.GetStringAsync());
        }
    }
}

您使用Task.Run来调用方法,而不是作为方法实现的一部分。