c# - 如何线程安全地将并行进程中的数据收集到单个对象中?
问题描述
我有以下发送多条短信的功能:
BulkSMSSenderResult bulkResult = new BulkSMSSenderResult();
if (BulkRequest.Requests.Any()) {
IEnumerable<(SMSSenderRequest, Task<Nito.Try<SMSSenderResult>>)> sendSmsTasks
= BulkRequest.Requests.Select(request => (request, SendSingleSmsAsync(request)));
await Task.WhenAll(sendSmsTasks.Select(task => task.Item2));
sendSmsTasks.ToList()
.ForEach(task => {
(SMSSenderRequest request, Task<Nito.Try<SMSSenderResult>> tryResult) = task;
_ = tryResult.Result.Match<Either<ErrorMessage, SMSSenderResult>>(
exception => new ErrorMessage(exception, request),
value => value
)
.Match(
result => bulkResult.Add(result),
error => bulkResult.Add(error)
);
});
}
if (BulkRequest.BadRequests.Any()) {
bulkResult.InvalidRequests = BulkRequest.BadRequests;
}
WriteResponseAsync(context, StatusCodes.Status207MultiStatus, bulkResult);
这几乎可以按预期工作,只是似乎所有 SMS 都被发送了两次。
我认为问题可能出在这一行:
await Task.WhenAll(sendSmsTasks.Select(task => task.Item2));
我的期望是这条线应该检查 SMS 是否已发送,以便后面的代码可以安全执行。
但是,似乎这行和后面的代码都导致SendSingleSmsAsync(request)
执行......或者其他东西(我无法推测)导致工作两次触发(我确信SendSingleSmsAsync(request)
它本身工作正常)。
任何想法如何解决这一问题?
解决方案
您必须将可枚举的 Linq 操作更多地视为设置要执行的小迷你程序,而不是实际运行它们。
在您的情况下,您在此处设置计算:
IEnumerable<(SMSSenderRequest, Task<Nito.Try<SMSSenderResult>>)> sendSmsTasks
= BulkRequest.Requests.Select(request => (request, SendSingleSmsAsync(request)))
但是你实际上经历并执行了两次 - 这里:
await Task.WhenAll(sendSmsTasks.Select(task => task.Item2));
和这里:
sendSmsTasks.ToList()
解决方法是尽快“实现”可枚举,以便从那时起您处理的是实际数据,而不是可链接的、懒惰的、可能的东西。
尝试坚持.ToArray()
在可枚举的声明的末尾。
推荐阅读
- javascript - 我应该如何在 axios GET 请求中发送 JWT 令牌?
- linux - Powershell POST 到 Linux curl
- html - 引导卡作为显示数据的按钮
- ansible - Ansible:在循环中合并stdout_results dict项目的元素
- r - LSTM 理解,可能的过拟合
- jupyter-notebook - 在 Google Colab 上安装 jupyter-contrib-nbextension
- arm - 仅当另一个进程正在运行时,从我系统中的 UART 设备传输到 CPU 的保持活动消息不会偶尔到达
- php - 隐藏或显示特定自定义分类类别中的 div
- tensorflow - keras.callbacks.Tensorboard 在 Tensorflow 急切执行中不起作用
- javascript - 在加载时调用多个指令并单击一个指令