我已经通读了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)。
在任务。工厂。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));
如果您是CPU绑定(您是-处理器时间拍摄高达100%),您需要减少CPU使用。异步IO对此没有任何帮助。如果有什么不同的话,它会导致更多的CPU使用(此处不明显)。
分析应用程序,看看什么需要这么多的CPU时间,并优化代码。
您启动并行(并行、任务、异步IO)的方式对并行操作本身的效率没有任何影响。如果您以异步方式调用网络,网络不会变得更快。它仍然是相同的硬件。也不会减少CPU占用。
通过实验确定最佳并行度,并选择适合该度的并行技术。如果是几十个线程,那么完全可以。如果是数百个,请认真考虑异步IO。
进行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