gpt4 book ai didi

c# - 超时使用 TaskCompletionSource 实现的异步方法

转载 作者:IT王子 更新时间:2023-10-29 04:42:33 25 4
gpt4 key购买 nike

我有一个黑盒对象,它公开了一个方法来启动异步操作,并在操作完成时触发一个事件。我把它包装成 Task<OpResult> BlackBoxOperationAysnc()使用 TaskCompletionSource 的方法 - 效果很好。

但是,在该异步包装器中,如果在给定超时后未收到事件,我想管理完成异步调用并出现超时错误。目前我用一个计时器来管理它:

public Task<OpResult> BlackBoxOperationAysnc() {
var tcs = new TaskCompletionSource<TestResult>();
const int timeoutMs = 20000;
Timer timer = new Timer(_ => tcs.TrySetResult(OpResult.Timeout),
null, timeoutMs, Timeout.Infinite);

EventHandler<EndOpEventArgs> eventHandler = (sender, args) => {
...
tcs.TrySetResult(OpResult.BlarBlar);
}
blackBox.EndAsyncOpEvent += eventHandler;
blackBox.StartAsyncOp();
return tcs.Task;
}

这是管理超时的唯一方法吗?有没有设置我自己的计时器的方法 - 我看不到 TaskCompletionSource 中内置的任何超时?

最佳答案

你可以使用 CancellationTokenSource超时。将它与您的 TaskCompletionSource 一起使用,例如 this .

例如:

public Task<OpResult> BlackBoxOperationAysnc() {
var tcs = new TaskCompletionSource<TestResult>();

const int timeoutMs = 20000;
var ct = new CancellationTokenSource(timeoutMs);
ct.Token.Register(() => tcs.TrySetCanceled(), useSynchronizationContext: false);

EventHandler<EndOpEventArgs> eventHandler = (sender, args) => {
...
tcs.TrySetResult(OpResult.BlarBlar);
}
blackBox.EndAsyncOpEvent += eventHandler;
blackBox.StartAsyncOp();
return tcs.Task;
}

已更新,这是一个完整的功能示例:

using System;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication
{
public class Program
{
// .NET 4.5/C# 5.0: convert EAP pattern into TAP pattern with timeout
public async Task<AsyncCompletedEventArgs> BlackBoxOperationAsync(
object state,
CancellationToken token,
int timeout = Timeout.Infinite)
{
var tcs = new TaskCompletionSource<AsyncCompletedEventArgs>();
using (var cts = CancellationTokenSource.CreateLinkedTokenSource(token))
{
// prepare the timeout
if (timeout != Timeout.Infinite)
{
cts.CancelAfter(timeout);
}

// handle completion
AsyncCompletedEventHandler handler = (sender, args) =>
{
if (args.Cancelled)
tcs.TrySetCanceled();
else if (args.Error != null)
tcs.SetException(args.Error);
else
tcs.SetResult(args);
};

this.BlackBoxOperationCompleted += handler;
try
{
using (cts.Token.Register(() => tcs.SetCanceled(), useSynchronizationContext: false))
{
this.StartBlackBoxOperation(null);
return await tcs.Task.ConfigureAwait(continueOnCapturedContext: false);
}
}
finally
{
this.BlackBoxOperationCompleted -= handler;
}
}
}

// emulate async operation
AsyncCompletedEventHandler BlackBoxOperationCompleted = delegate { };

void StartBlackBoxOperation(object state)
{
ThreadPool.QueueUserWorkItem(s =>
{
Thread.Sleep(1000);
this.BlackBoxOperationCompleted(this, new AsyncCompletedEventArgs(error: null, cancelled: false, userState: state));
}, state);
}

// test
static void Main()
{
try
{
new Program().BlackBoxOperationAsync(null, CancellationToken.None, 1200).Wait();
Console.WriteLine("Completed.");
new Program().BlackBoxOperationAsync(null, CancellationToken.None, 900).Wait();
}
catch (Exception ex)
{
while (ex is AggregateException)
ex = ex.InnerException;
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
}
}

可以找到 .NET 4.0/C# 4.0 版本 here ,它利用了编译器生成的 IEnumerator 状态机。

关于c# - 超时使用 TaskCompletionSource 实现的异步方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18760252/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com