gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-03 21:13:44 25 4
gpt4 key购买 nike

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

任务 - 从 Internet 加载位图。之前,我只是同步地一个接一个地加载它们。异步加载它们会更快地给出结果。下面,我举了两个示例,说明如何获取单个图像 - GetImageGetImageAsync。对于图像列表,我会使用 LoadImagesLoadImages2

LoadImages 将以异步方式运行同步函数(所有同时(?)),LoadImages2 将以异步方式运行异步函数并产生相同的结果(?) .我不完全理解的事情 - 在 GetImageAsync await request.GetResponseAsync() 中。我真的需要它吗?这是做同样事情的“更好”方式吗? LoadImagesLoadImages2 之间真的有什么区别吗?

目前,我正在考虑选择 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;
}

最佳答案

这里的术语和技术选择有些困惑。

Before, I was just loading them 1 by 1, in sync. Loading them in async would give results quicker.

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

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

LoadImages 是对同步代码使用并行性的示例。这种方法的优点是它使顶层方法保持同步,因此调用代码无需更改。缺点是它在资源使用方面很浪费,并且在概念上不适合底层发生的事情(I/O 绑定(bind)代码更自然地由异步 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]);
}

附言如果您确实决定使用(同步)LoadImages,您将需要修复一个竞争条件,在该条件下,各种并行线程都将尝试更新字典而不锁定它。

关于C# 在同步上下文中运行异步任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35914053/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com