我在C#异步方面没有太多经验。
任务-从Internet加载位图。以前,我只是按1个1个同步地加载它们。异步加载它们可以更快地得到结果。在下面,我举了两个例子,我如何获得单个图像-GetImage
和GetImageAsync
。对于图像列表,我将使用LoadImages
和LoadImages2
。
LoadImages
将在异步中运行同步功能(全部同时(?)),LoadImages2
将在异步中运行异步功能并产生相同的结果(?)。我不完全了解的东西-in GetImageAsync
await request.GetResponseAsync()
。我真的需要吗?这是做同一件事的一种“更好”的方式吗?LoadImages
和之间真的有任何区别吗LoadImages2
?
目前,我正在考虑选择GetImage
和LoadImages
选择。另外,我不想用来装饰每个函数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] 删除。
我来说两句