C#在同步上下文中运行异步任务

希望

我在C#异步方面没有太多经验。

任务-从Internet加载位图。以前,我只是按1个1个同步地加载它们。异步加载它们可以更快地得到结果。在下面,我举了两个例子,我如何获得单个图像-GetImageGetImageAsync对于图像列表,我将使用LoadImagesLoadImages2

LoadImages将在异步中运行同步功能(全部同时(?)),LoadImages2将在异步中运行异步功能并产生相同的结果(?)。我不完全了解的东西-in GetImageAsync await request.GetResponseAsync()我真的需要吗?这是做同一件事的一种“更好”的方式吗?LoadImages之间真的有任何区别吗LoadImages2

目前,我正在考虑选择GetImageLoadImages选择。另外,我不想用来装饰每个函数async Task,我只需要异步加载这些图像即可。

public Bitmap GetImage(string url)
{
    HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
    using (WebResponse response = request.GetResponse())
    using (Stream responseStream = response.GetResponseStream())
        return new Bitmap(responseStream);
}

public async Task<Bitmap> GetImageAsync(string url)
{
    HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
    using (WebResponse response = await request.GetResponseAsync())
    using (Stream responseStream = response.GetResponseStream())
        return new Bitmap(responseStream);
}

private Dictionary<string, Bitmap> LoadImages(List<string> urls)
{
    Dictionary<string, Bitmap> images = new Dictionary<string, Bitmap>();
    Task.WaitAll(urls.Select(url => 
        Task.Run(() =>
        {
            images.Add(url, GetImage(url));
        })).ToArray());
    return images;
}

private Dictionary<string, Bitmap> LoadImages2(List<string> urls)
{
    Dictionary<string, Bitmap> images = new Dictionary<string, Bitmap>();
    Task.WhenAll(urls.Select(url =>
        Task.Run(async () =>
        {
            images.Add(url, await GetImageAsync(url));
        })));
    return images;
}
斯蒂芬·克莱里

这里的术语和技术选择有些混乱。

以前,我只是按1个1个同步地加载它们。异步加载它们可以更快地得到结果。

您的意思是串行并发,而不是同步异步串行是一次一次,而并发是一次多个事情。同步代码可以是串行或并发的,异步代码可以是串行或并发的。

其次,并发并行Task.Run是并行的一种形式,这是一种通过向问题中添加线程来实现并发的方法。异步是一种通过释放线程来实现并发的方法

LoadImages是在同步代码中使用并行性的示例。这种方法的优点是它使顶级方法保持同步,因此无需更改任何调用代码。缺点是,这在资源使用方面很浪费,并且与下面发生的事情没有很好的概念契合(I / O绑定代码更自然地由异步API表示)。

LoadImages2是并行和异步代码的混合,这有点令人困惑。没有线程(即),异步并发更容易表示Task.Run返回值而不是将集合更新作为副作用也更自然。因此,如下所示:

private async Task<Dictionary<string, Bitmap>> LoadImagesAsync(List<string> urls)
{
  Bitmap[] result = await Task.WhenAll(urls.Select(url => GetImageAsync(url)));

  return Enumerable.Range(0, urls.Length).ToDictionary(i => urls[i], i => result[i]);
}

PS:如果您决定使用(同步)LoadImages,则需要修复一个争用条件,其中各种并行线程将全部尝试更新字典而不锁定它。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

Related 相关文章

热门标签

归档