当前位置: 首页 > 知识库问答 >
问题:

任务。StartNew()vs并行。每个:多个网络请求场景

鲁光霁
2023-03-14

我已经通读了SO中的所有相关问题,但对于触发多个web服务调用的场景的最佳方法有点困惑。

我有一个聚合器服务,它接收输入,解析并将其转换为多个web请求,进行web请求调用(不相关,因此可以并行启动),并整合发送回调用方的响应。下面的代码正在使用-

list.ForEach((object obj) =>
{
     tasks.Add(Task.Factory.StartNew((object state) => 
     {
           this.ProcessRequest(obj);
     }, obj, CancellationToken.None,
     TaskCreationOptions.AttachedToParent, TaskScheduler.Default));
});
await Task.WhenAll(tasks);

等待任务。WhenAll(任务)来自Scott Hanselman的帖子,据说

"Stephen说,从可伸缩性的角度来看,一个更好的解决方案是利用异步I/O。当你在网络上呼叫时,没有理由(除了方便)在等待响应返回时阻塞线程。"

现有代码似乎消耗了太多线程,处理器时间在生产负载上激增到100%,这让我思考。

另一种选择是使用并行。ForEach使用了分区器,但也“阻止”了调用,这对我的场景来说很好。

考虑到这都是“异步IO”工作,而不是“CPU绑定”工作,而且web请求运行时间不长(最多3秒后返回),我倾向于相信现有代码已经足够好了。但这会比并行提供更好的吞吐量吗。弗雷奇?平行的ForEach可能使用“最小”数量的任务,因为它是分区的,因此线程的最佳使用(?)。我做了平行测试。ForEach进行了一些本地测试,结果似乎没有任何好转。

目标是减少CPU时间,提高吞吐量,从而提高可扩展性。有没有更好的方法来并行处理web请求?

感谢任何意见,谢谢。

编辑:代码示例中显示的ProcessRequest方法确实使用HttpClient及其异步方法来触发请求(PostAsync、GetAsync、PutAsync)。

共有3个答案

姚煜
2023-03-14

在任务。工厂。StartNew中包装同步调用不会给您带来异步的任何好处。您应该使用适当的异步函数来获得更好的可伸缩性。请注意斯科特·汉塞尔曼在您提到的帖子中是如何制作异步函数的。

例如

public async Task<bool> ValidateUrlAsync(string url)
{
    using(var response = (HttpWebResponse)await WebRequest.Create(url).GetResponseAsync())
    return response.StatusCode == HttpStatusCode.Ok;
}

结帐http://blogs.msdn.com/b/pfxteam/archive/2012/03/24/10287244.aspx

因此,ProcessRequest方法应该像异步一样实现

public async Task<bool> ProcessRequestAsync(...)

那你就可以

tasks.Add(this.ProcessRequestAsync(obj))

如果你以任务开始任务。工厂StartNew即使ProcessRequest方法在内部进行异步调用,它也不能以异步方式工作。如果你想使用任务。工厂中,您应该使lambda也异步,如:

tasks.Add(Task.Factory.StartNew(async (object state) => 
{
    await this.ProcessRequestAsync(obj);
}, obj, CancellationToken.None, TaskCreationOptions.AttachedToParent,   TaskScheduler.Default));
羊舌高明
2023-03-14

如果您是CPU绑定(您是-处理器时间拍摄高达100%),您需要减少CPU使用。异步IO对此没有任何帮助。如果有什么不同的话,它会导致更多的CPU使用(此处不明显)。

分析应用程序,看看什么需要这么多的CPU时间,并优化代码。

您启动并行(并行、任务、异步IO)的方式对并行操作本身的效率没有任何影响。如果您以异步方式调用网络,网络不会变得更快。它仍然是相同的硬件。也不会减少CPU占用。

通过实验确定最佳并行度,并选择适合该度的并行技术。如果是几十个线程,那么完全可以。如果是数百个,请认真考虑异步IO。

陆文斌
2023-03-14

进行Web请求调用(不相关,因此可以并行触发)

你真正想要的是同时调用它们,而不是并行调用。也就是说,“同时”,而不是“使用多个线程”。

现有代码似乎占用了太多线程

是的,我也这么认为。:)

考虑到这都是“异步IO”工作,而不是“CPU绑定”工作

然后这一切都应该异步完成,而不是使用任务并行性或其他并行代码。

正如Antii指出的,你应该让你的异步代码异步:

public async Task ProcessRequestAsync(...);

然后,您要做的是使用异步并发(Task.whalll),而不是并行并发(StartNew/Run/parallel):

await Task.WhenAll(list.Select(x => ProcessRequestAsync(x)));
 类似资料:
  • 我试着用一个实例并行运行许多计划任务,每一个我这样配置任务 但是有很多实例每秒开始,而第一个实例尚未完成。是否可以同时配置任务运行的一个实例?我的豆子配置在Spring调度器.xml

  • 我有大约5个与从HTTP获取数据以及基于数据处理和生成结果相关的任务。 我希望并行运行这些任务,并等待所有任务成功完成或其中一个任务失败。每个任务都应该能够发布失败原因。如果其中一项任务失败,那么所有任务都将被视为失败,并在不等待所有任务完成的情况下退出。 我试图使用完整的未来和未来列表来实现它,但它不起作用,代码也不能很好地发布。 我有没有更好的方法来实现它?以身作则会有所帮助。

  • 我们有一个场景,每个Cassandra中给定,对于下面的架构: 单个 POST 请求正文包含多个值的详细信息。这将触发单个表上每个 POST 请求的多个插入。 每个INSERT查询如下所示执行: 1个 Cassandra是否确保每个POST请求在单个表上的多个插入上的数据展示一致性?每个POST请求都在Go例程(线程)上处理。后续GET请求应确保检索一致的数据(通过POST插入) 使用批处理语句在

  • 问题内容: 我有以下使用类的课程。所以我想做的是,在运行cp1实例处理方法的同时,我要并行运行。 但是,我要按顺序cp1,所以我要它运行并完成,如果cp2没有完成或失败,那就很好。如果确实失败,我想加入结果。该示例中未返回任何内容,但我想返回结果。 为此,应该使用TaskExecutor吗?还是线程? 我只希望cp2与cp1并行运行。或者,如果我添加更多内容,例如说cp3,我希望它也可以与cp1并

  • 我的makefile中的一个目标是一个非常耗时的CPU任务。但是我可以分割工作负载并并行运行任务几次,以加快整个过程。 我的问题是make不会等待所有过程完成。 考虑一下这个简单的脚本,名为“代码> MyTask.SH <代码>: 现在,让我们从bash脚本调用它,并使用等待所有任务完成: 产出如预期: 但是在Makefile中尝试相同的方法时: 它不起作用: 当然,我可以创建多个目标,这些目标可

  • 在当今99%的移动应用中网络都是必不可缺的一部分:总是需要连接远程服务器来检索App需要的信息。 作为网络访问的第一个案例,我们将创建下面这样一个场景: 加载一个进度条。 用一个按钮开始文件下载。 下载过程中更新进度条。 下载完后开始视频播放。 我们的用户界面非常简单,我们只需要一个有趣的进度条和一个下载按钮。 首先,我们创建mDownloadProgress private PublishSub