我正在开发一个
async
应用程序,该应用程序使用来自一个系统的键值对数据填充字典,然后使用该字典确定第二个系统是否具有匹配的数据。问题在于,在其他线程尝试查找键值对中的数据之前,字典没有完成填充其数据,从而产生不正确的结果。
我尝试将原始代码(一个 void 方法)转换为返回任务的异步方法。像这样开始的东西
async Task<Dictionary<string, string>> CreateGALEmailTypesDictionary(IEnumerable<InterActionQueryResult_BaseClass>? interActionClientAllRecords, SearchResultCollection ADClientAllRecords)
但是因为该方法内部的所有逻辑都依赖于条件语句并且没有额外的异步,所以我看不到使用
await
或 Task.WhenAll
的方法。
下面是填充字典的原始代码。我如何在异步应用程序中使用此逻辑并确保在任何其他进程读取其中包含的数据之前填充字典?
public void ReviewGALEmailTypesForDeletions(IEnumerable<InterActionQueryResult_BaseClass>? interActionClientAllRecords, SearchResultCollection ADClientAllRecords)
{
string? InterAction_GAL_EmailType = string.Empty;
string? AD_GAL_EmailTypeInInterAction = string.Empty;
if (interActionClientAllRecords is not null)
{
Dictionary<string, string> InterActionGALEmailTypes = new Dictionary<string, string>();
foreach (InterActionQueryResult_BaseClass interActionClientRecord in interActionClientAllRecords)
{
//InterAction GAL Email Types can contain spaces, but AD GAL Email Types cannot. Spaces removed for later matching.
if (interActionClientRecord.InterActionEmailType is null)
InterAction_GAL_EmailType = string.Empty;
else
InterAction_GAL_EmailType = interActionClientRecord.InterActionEmailType.Replace(" ", string.Empty);
if (interActionClientRecord.GALEmailType is null)
interActionClientRecord.GALEmailType = string.Empty;
else
AD_GAL_EmailTypeInInterAction = interActionClientRecord.GALEmailType.Replace(" ", string.Empty);
if (!InterActionGALEmailTypes.ContainsKey(InterAction_GAL_EmailType))
InterActionGALEmailTypes.Add(InterAction_GAL_EmailType, AD_GAL_EmailTypeInInterAction);
}
//Look up ADClientAllRecords in dictionary
您不需要使用
async
来生成 Task
。考虑这个例子:
Task<Dictionary<string, string>> instance;
Task<Dictionary<string, string>> GetInstanceAsync()
{
if (instance != null)
{
return instance;
}
var completionSource = new TaskCompletionSource<Dictionary<string, string>>();
instance = completionSource.Task;
var dictionary = new Dictionary<string, string>();
// Populate Dictionary //
completionSource.SetResult(dictionary);
return completionSource;
}
一旦设置了
instance
,以后调用此函数将从 TaskCompletionSource 返回任务。该任务的任何继续操作只会在此函数调用 SetResult
后执行。
请注意,为简单起见,这不会锁定线程,因此有可能多个线程最终完成初始化字典的工作。仅当初始化字典是“幂等”操作时,这才是安全的。它大致类似于使用 Lazy<T>
和
LazyThreadSafetyMode.PublicationOnly
。事实上,我建议您考虑使用
Lazy<T>
来代替:此代码给您的唯一优点是其他任务可以异步
await
任务,在等待字典的同时释放线程以供其他用途。创建的。除非需要花费很长时间来创建字典,否则您最好允许这些线程阻塞并避免使用
Task
s 带来的额外复杂性和开销。