SiS*_*arp 0 c# asynchronous parallel.foreach
我在列表中有几个对象。每分钟,对于他们每个人,我都必须下载api信息并将接收到的数据保存到数据库中。
列表中的对象彼此独立。每个对象的方法可以单独调用。根据 api 的响应时间,单个方法的总执行时间通常为 ~0.5 到 5 秒。
按照 stackoverflow 上其他线程中的建议,我创建了以下代码:
private async void DownloadAndSaveDataForMyObjects(object state)
{
try
{
await Task.Run(() => Parallel.ForEach(MyObjectsList, ServiceSingleObjectMethod));
}
}
private void ServiceSingleObjectMethod(RehDeviceSmsRequest myObjectFromList)
{
var apiInfo = GetInfoFromApi(myObjectFromList);
SaveInfoToDatabase(myObjectFromList);
}
Run Code Online (Sandbox Code Playgroud)
在我看来,代码是异步的。但是……我有些怀疑。Logger 通知我应用程序运行期间执行的操作。对象的方法调用之间的间隔非常大。请看这个:
[13:32:46 DBG][MyService]->MyMethod => Update object id: 54
[13:32:47 DBG][MyService]->MyMethod => Update object id: 9
[13:32:50 DBG][MyService]->MyMethod => Update object id: 47
[13:32:51 DBG][MyService]->MyMethod => Update object id: 21
[13:32:51 DBG][MyService]->MyMethod => Update object id: 53
[13:32:53 DBG][MyService]->MyMethod => Update object id: 37
[13:32:55 DBG][MyService]->MyMethod => Update object id: 62
[13:32:55 DBG][MyService]->MyMethod => Update object id: 63
[13:32:56 DBG][MyService]->MyMethod => Update object id: 64
[13:32:56 DBG][MyService]->MyMethod => Update object id: 55
[13:32:56 DBG][MyService]->MyMethod => Update object id: 36
[13:32:56 DBG][MyService]->MyMethod => Update object id: 30
[13:32:56 DBG][MyService]->MyMethod => Update object id: 46
[13:32:56 DBG][MyService]->MyMethod => Update object id: 26
[13:32:56 DBG][MyService]->MyMethod => Update object id: 56
[13:33:00 DBG][MyService]->MyMethod => Update object id: 29
[13:33:00 DBG][MyService]->MyMethod => Update object id: 57
[13:33:00 DBG][MyService]->MyMethod => Update object id: 42
[13:33:01 DBG][MyService]->MyMethod => Update object id: 38
[13:33:01 DBG][MyService]->MyMethod => Update object id: 32
[13:33:01 DBG][MyService]->MyMethod => Update object id: 48
[13:33:01 DBG][MyService]->MyMethod => Update object id: 40
[13:33:01 DBG][MyService]->MyMethod => Update object id: 31
[13:33:01 DBG][MyService]->MyMethod => Update object id: 49
[13:33:02 DBG][MyService]->MyMethod => Update object id: 58
[13:33:02 DBG][MyService]->MyMethod => Update object id: 9
[13:33:02 DBG][MyService]->MyMethod => Update object id: 33
[13:33:02 DBG][MyService]->MyMethod => Update object id: 41
[13:33:04 DBG][MyService]->MyMethod => Update object id: 50
[13:33:04 DBG][MyService]->MyMethod => Update object id: 34
[13:33:06 DBG][MyService]->MyMethod => Update object id: 17
[13:33:06 DBG][MyService]->MyMethod => Update object id: 59
[13:33:07 DBG][MyService]->MyMethod => Update object id: 45
[13:33:08 DBG][MyService]->MyMethod => Update object id: 61
[13:33:08 DBG][MyService]->MyMethod => Update object id: 54
[13:33:08 DBG][MyService]->MyMethod => Update object id: 43
[13:33:08 DBG][MyService]->MyMethod => Update object id: 51
[13:33:08 DBG][MyService]->MyMethod => Update object id: 52
Run Code Online (Sandbox Code Playgroud)
处理后续对象之间的间隔非常大。我认为我的异步代码将使每个对象的方法同时被调用(或非常非常相似)......
如何确保我的代码是异步的并且正常工作?你能确认我正确地为每个对象调用任务吗?
Parallel.ForEach不会主动从线程池中释放线程。该任务调度程序将决定多少线程你应该使用,并根据核心,你的系统已经在做,并将其从您的任务收集的启发,它可能不会做你所期望。
但是,这里有更大的概念问题。您正在使用Parallel.ForEach(看起来是)基本的IO 绑定工作,这是捆绑/阻塞线程,可以更合适地卸载到IO 完成端口,反过来有更大的机会实现更多并发IO 绑定工作负载。
简而言之,它Parallel.ForEach不适合IO 密集型工作负载,它针对CPU 密集型工作负载进行了优化,并且不支持async 和 await 模式。
总之,你应该让你的IO方法是异步(一路下跌),并使用更合适的技术,可以处理异步并等待模式,像Task.WhenAll或TPL数据流 ActionBlock<T>或反应扩展。此外,您可能应该将您的工作批处理到数据库中,这样您也不会遇到麻烦。这将为您的工作负载提供最好的机会,而不是阻塞线程池线程,反过来您可能会发现吞吐量(通常)会高得多。
| 归档时间: |
|
| 查看次数: |
89 次 |
| 最近记录: |