带有记录和锁的异步实现
async implementation with records and lock
我担心我的代码中存在竞争条件情况。
我有这个从数据库中获取信息的函数:
public async Task ExecuteBroadcasts()
{
List<Broadcast> broadcasts =_iSMSFetcherUnitOfWork.GetAllBroadCastsInPastTimeThatDidntRun();
foreach (Broadcast broadcast in broadcasts)
{
foreach (SenderPhone sender in broadcast.SenderPhoneList.SenderPhones)
{
foreach (ReceiverPhone receiverPhone in broadcast.RecipeintPhoneList.ReceiverPhones)
{
var tasks= broadcast.RecipeintPhoneList.ReceiverPhones.Select(receiverPhone => _iSMSProcessorAndSender.ProcessSMSes(new PreProcessedSMS(sender.Phone, receiverPhone, broadcast.SMSTemplate))).ToArray();
await Task.WhenAll(tasks);
}
}
}
}
这种类型'PreProcessedSMS'是一条记录。 ProcessSMSes 是一个函数,它将从数据库中获取的信息发送到 SMS 提供商。下面是这个函数的内容。
public async Task ProcessSMSes(PreProcessedSMS preProcessedSMS)
{
_iSMSExpressionInterpreter.ReceiverPhone = preProcessedSMS.receiverPhoneObj;
object sync = new object();
string smsBody = string.Empty;
lock (sync) smsBody = preProcessedSMS.sMSTemplate;
Task longRunning = Task.Factory.StartNew(() =>
{
smsBody = _iSMSExpressionInterpreter.TranslateSpinner(preProcessedSMS.sMSTemplate);
});
await longRunning.ContinueWith(async (sms) =>
{
smsBody = _iSMSExpressionInterpreter.TranslateFirstName(smsBody);
smsBody = _iSMSExpressionInterpreter.TranslateLastName(smsBody);
smsBody = _iSMSExpressionInterpreter.TranslateCustom(smsBody);
smsBody = _iSMSExpressionInterpreter.TranslateUnsubscribe(smsBody);
await _iSMSDispatcher.SendSMS(new SMSRecord(preProcessedSMS.senderPhone, preProcessedSMS.receiverPhoneObj.Phone, smsBody));
}, TaskContinuationOptions.NotOnFaulted);
longRunning.Start();
}
我锁定了 'smsBody' 参数,因为担心下一个函数执行会为其设置不同的值。我对实施持谨慎态度。在不遇到可能的竞争条件的情况下高效执行代码的最佳方法是什么。
更新:
public async Task ProcessSMSes(PreProcessedSMS preProcessedSMS)
{
await Task.Run(async () =>
{
_iSMSExpressionInterpreter.ReceiverPhone = preProcessedSMS.receiverPhoneObj;
string smsBody = _iSMSExpressionInterpreter.TranslateSpinner(preProcessedSMS.sMSTemplate);
smsBody = _iSMSExpressionInterpreter.TranslateFirstName(smsBody);
smsBody = _iSMSExpressionInterpreter.TranslateLastName(smsBody);
smsBody = _iSMSExpressionInterpreter.TranslateCustom(smsBody);
smsBody = _iSMSExpressionInterpreter.TranslateUnsubscribe(smsBody);
await _iSMSDispatcher.SendSMS(new SMSRecord(preProcessedSMS.senderPhone, preProcessedSMS.receiverPhoneObj.Phone, smsBody));
});
}
lock
s 仅在其他所有内容也使用相同的 lock
时才有效。在这种情况下,您将锁定一个局部变量,它什么都不做。您不能使用锁来防止任何其他代码更改任何内容。在这种情况下,您 可以 在 sMSTemplate
的实现中使用 lock
,这样每次 read/written,它都使用 lock
,但这似乎很奇怪。我建议明智地使用锁,其中多线程访问是 预期的,而不是“出于恐惧”。
旁注:
- Don't use
Task.Factory.StartNew
;如果您想 运行 在线程池线程上编写代码,请使用 Task.Run
。
- Don't use
ContinueWith
;请改用 await
。
我担心我的代码中存在竞争条件情况。
我有这个从数据库中获取信息的函数:
public async Task ExecuteBroadcasts()
{
List<Broadcast> broadcasts =_iSMSFetcherUnitOfWork.GetAllBroadCastsInPastTimeThatDidntRun();
foreach (Broadcast broadcast in broadcasts)
{
foreach (SenderPhone sender in broadcast.SenderPhoneList.SenderPhones)
{
foreach (ReceiverPhone receiverPhone in broadcast.RecipeintPhoneList.ReceiverPhones)
{
var tasks= broadcast.RecipeintPhoneList.ReceiverPhones.Select(receiverPhone => _iSMSProcessorAndSender.ProcessSMSes(new PreProcessedSMS(sender.Phone, receiverPhone, broadcast.SMSTemplate))).ToArray();
await Task.WhenAll(tasks);
}
}
}
}
这种类型'PreProcessedSMS'是一条记录。 ProcessSMSes 是一个函数,它将从数据库中获取的信息发送到 SMS 提供商。下面是这个函数的内容。
public async Task ProcessSMSes(PreProcessedSMS preProcessedSMS)
{
_iSMSExpressionInterpreter.ReceiverPhone = preProcessedSMS.receiverPhoneObj;
object sync = new object();
string smsBody = string.Empty;
lock (sync) smsBody = preProcessedSMS.sMSTemplate;
Task longRunning = Task.Factory.StartNew(() =>
{
smsBody = _iSMSExpressionInterpreter.TranslateSpinner(preProcessedSMS.sMSTemplate);
});
await longRunning.ContinueWith(async (sms) =>
{
smsBody = _iSMSExpressionInterpreter.TranslateFirstName(smsBody);
smsBody = _iSMSExpressionInterpreter.TranslateLastName(smsBody);
smsBody = _iSMSExpressionInterpreter.TranslateCustom(smsBody);
smsBody = _iSMSExpressionInterpreter.TranslateUnsubscribe(smsBody);
await _iSMSDispatcher.SendSMS(new SMSRecord(preProcessedSMS.senderPhone, preProcessedSMS.receiverPhoneObj.Phone, smsBody));
}, TaskContinuationOptions.NotOnFaulted);
longRunning.Start();
}
我锁定了 'smsBody' 参数,因为担心下一个函数执行会为其设置不同的值。我对实施持谨慎态度。在不遇到可能的竞争条件的情况下高效执行代码的最佳方法是什么。
更新:
public async Task ProcessSMSes(PreProcessedSMS preProcessedSMS)
{
await Task.Run(async () =>
{
_iSMSExpressionInterpreter.ReceiverPhone = preProcessedSMS.receiverPhoneObj;
string smsBody = _iSMSExpressionInterpreter.TranslateSpinner(preProcessedSMS.sMSTemplate);
smsBody = _iSMSExpressionInterpreter.TranslateFirstName(smsBody);
smsBody = _iSMSExpressionInterpreter.TranslateLastName(smsBody);
smsBody = _iSMSExpressionInterpreter.TranslateCustom(smsBody);
smsBody = _iSMSExpressionInterpreter.TranslateUnsubscribe(smsBody);
await _iSMSDispatcher.SendSMS(new SMSRecord(preProcessedSMS.senderPhone, preProcessedSMS.receiverPhoneObj.Phone, smsBody));
});
}
lock
s 仅在其他所有内容也使用相同的 lock
时才有效。在这种情况下,您将锁定一个局部变量,它什么都不做。您不能使用锁来防止任何其他代码更改任何内容。在这种情况下,您 可以 在 sMSTemplate
的实现中使用 lock
,这样每次 read/written,它都使用 lock
,但这似乎很奇怪。我建议明智地使用锁,其中多线程访问是 预期的,而不是“出于恐惧”。
旁注:
- Don't use
Task.Factory.StartNew
;如果您想 运行 在线程池线程上编写代码,请使用Task.Run
。 - Don't use
ContinueWith
;请改用await
。