如何使用timout取消TaskCompletionSource我有一个使用await关键字异步调用的函数:publicTaskRequestStateForEntity(EntityKeyentity,stringpropName){vartcs=new任务完成源();尝试{varpropInstance=BuildCacheKey(entity,propName);StateCacheItem缓存项;if(_stateCache.TryGetValue(propInstance,outcacheItem)){tcs.SetResult(newStateInfo(cacheItem.State.Name,cacheItem.State.Value));返回tcs.Task;}//在本地缓存中找不到状态所以保存tcs以备后用并请求状态varcacheKey=BuildCacheKey(entity,propName);_stateRequestItemList.TryAdd(cacheKey,newStateRequestItem(entity,propName,tcs));_evtClient.SubmitStateRequest(entity,propName);返回tcs.Task;}catch(Exceptionex){tcs.SetException(ex);返回tcs.Task;}}该函数检查它是否有它需要的信息,如果有,则返回它。如果它没有详细信息,它会发送一个最终应作为事件发送的请求。此时,我的代码(未显示)找到存储的TaskCompletionSource项,设置结果并返回它。这一切都很好,但我现在被要求考虑一种情况,当我通过“_evtClient.SubmitStateRequest(entity,propName);”请求状态时。行,可能永远不会返回回复。我需要实施某种超时机制,以便我可以取消TCS任务,以便函数调用者可以优雅地失败。我一直在寻找SO和互联网,但找不到任何看起来正确的东西。我现在不确定是否需要以不同方式重构上述代码。任何人都可以建议或指出我类似的情况吗?调用上述函数的代码可以像这样单击调用它:varstateProperty=awaitRequestStateForEntity(key,stateName);或像这样分批处理:awaitTask.WhenAll(stateDefinitions.Select(stateDefinition=>stateDefinition.Name).Select(stateName=>Task.Factory.StartNew(async()=>results.Add(awaitRequestStateForEntity(key,stateName))).Unwrap()).ToArray());首先,您真正想要启用的是取消。取消来自超时的事实只是一个脚注。.NET有一些很好的内置取消支持,基于任务的异步模式决定了如何使用它。基本上,您要做的是获取CancellationToken:TaskRequestStateForEntity(EntityKeyentity,stringpropName,CancellationTokencancellationToken);接下来,您想在该令牌发出信号时做出响应。理想情况下,您只需要将CancellationToken传递给_evtClient即可实际取消请求:_evtClient.SubmitStateRequest(entity,propName,cancellationToken);这是实现取消的正常方法,如果SubmitStateRequest已经理解取消,它会很好用。通常,事件参数有一个指示取消的标志(例如,AsyncCompletedEventArgs.Cancelled)。如果可能,请使用此方法(即,如有必要,更改_evtClient以支持取消)。但有时这是不可能的。在这种情况下,您可以选择假装支持取消。如果请求在完成后被取消,您实际上正在做的只是忽略请求。这不是最理想的情况,但有时您别无选择。就个人而言,我不喜欢这种方法,因为它使API变得“谎言”:方法签名声称支持取消,但实际上只是假装支持。首先,我建议对此进行记录。为_evtClient代码注释道歉,解释说_evtClient不支持取消,“取消”实际上只是假装被取消。然后,当状态请求项在列表中但在发送实际请求之前,您需要自己挂接到CancellationToken:varitem=newStateRequestItem(entity,propName,tcs);_stateRequestItemList.TryAdd(cacheKey,item);item.CancellationRegistration=cancellationToken.Register(()=>{StateRequestItemcanceledItem;if(!_stateRequestItemList.TryRemove(cacheKey,outcancelledItem))return;cancelledItem.TaskCompletionSource.TrySetCanceled();});_evtClient.SubmitStateRequest(entity,propName);最后,您需要更新事件处理程序完成代码(未显示)以忽略状态请求项已被删除的情况,并在找到状态请求项时处理CancellationRegistration。一旦您的方法支持取消,就可以通过计时器轻松取消:varcts=newCancellationTokenSource(TimeSpan.FromSeconds(10));CancellationTokentoken=cts.Token;或来自任何其他情况。比如说,如果用户取消了他正在做的任何事情。或者,如果系统的另一部分决定不再需要该数据。一旦您的代码支持取消,它就可以处理任何原因的取消。您可以将CancellationToken传递给可以在内部实现取消逻辑的方法:publicTaskRequestStateForEntity(EntityKeyentity,stringpropName,CancellationTokentoken){try{//缓存检查_evtClient.SubmitStateRequest(entity,propName,token);返回tcs.Task;}catch(Exceptionex){tcs.SetException(ex);返回tcs.Task;在SubmitStateRequest内部:token.ThrowIfCancellationRequest();请注意ThrowIfCancellationRequest将抛出您需要处理的OperationCanceledException。如果是阻塞调用,可以使用TimeSpan在内部设置CancellationTokenSource:以上是C#学习教程:如何使用timout取消TaskCompletionSource的全部内容。如果对大家有用,需要进一步了解C#学习教程,希望大家多多关注——varcts=newCancellationTokenSource(TimeSpan.FromSeconds(10));本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
