1. Dotnet9首页
  2. .NET
  3. .NET相关

c# – 使用TaskCompletionSource实现异步方法

我有一个黑盒子对象暴露一个异步操作的方法,当操作完成时触发一个事件.我把它包装成一个任务< 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>();
 
            // prepare the timeout
            CancellationToken newToken;
            if (timeout != Timeout.Infinite)
            {
                var cts = CancellationTokenSource.CreateLinkedTokenSource(token);
                cts.CancelAfter(timeout);
                newToken = cts.Token;
            }
            else
                newToken = token;
 
            // 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 (newToken.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,900).Wait();
            }
            catch (Exception ex)
            {
                while (ex is AggregateException)
                    ex = ex.InnerException;
                Console.WriteLine(ex.Message);
            }
            Console.ReadLine();
        }
    }
}

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

总结

以上是脚本之家为你收集整理的c# – 使用TaskCompletionSource实现异步方法全部内容,希望文章能够帮你解决c# – 使用TaskCompletionSource实现异步方法所遇到的程序开发问题。

原文出处:脚本之家

原文链接:https://www.jb51.cc/csharp/92868.html

本文观点不代表Dotnet9立场,转载请联系原作者。

发表评论

登录后才能评论