使用Taskcompletion源创建无线程任务

本文关键字:线程 任务 创建 Taskcompletion 使用 | 更新日期: 2023-09-27 18:13:56

我的手被TPL弄脏了。我在TPL中偶然发现了一个名为TaskCompletionSource的主题,这是创建任务的方法之一,它允许开发人员设置结果、异常等,从而使您能够更好地控制任务

   public static Task<int> RunAsyncFunction(Func<int> sampleFunction)
    {
        if (sampleFunction == null)
            throw new NullReferenceException("Method cannot be null");
        var tcs = new TaskCompletionSource<int>();
        ThreadPool.QueueUserWorkItem(_ =>
        {
            try
            {
                int result = sampleFunction();
                tcs.SetResult(result);
            }
            catch (Exception ex)
            {
                tcs.SetException(ex);
            }
        });
        return tcs.Task;
    }

然而,这并不是真正的异步编程。它是使用多线程的异步编程。如何转换此示例以使其在单个线程而不是多个线程上运行?或者还有其他我可以效仿的例子吗?

使用Taskcompletion源创建无线程任务

为了实现异步,它需要一些容量才能在未来独立完成。这通常是通过以下两种方式之一:

  • 通过操作的回调,如套接字IO、文件IO、系统计时器等(可能导致重新激活的某些外部源(
  • 第二个线程(可能是一个排队的工作池线程,就像您的示例中一样(

如果您只有一个线程,没有外部回调,那么使用Task<T>就没有任何必要或意义。但是,您仍然可以通过现在简单地执行计算并立即设置结果来公开这一点——或者更简单地说:使用Task.FromResult

然而,您向显示的代码是真正异步的,或者更具体地说:您返回的Task<T>是异步的。这可能不是最好的用例,但本身并没有什么问题,只是您的整个方法可以极大地简化为:

return Task.Run(sampleFunction);

Task.Run<T>方法:

对要在线程池上运行的指定工作进行排队,并返回该工作的任务或任务句柄。

通常,如果我使用TaskCompletionSource,那是因为我正在编写基于IO回调的任务,而不是基于ThreadPool的任务;Task.Run适用于大多数情况。

TaskCompletionSource不会使代码异步。它是一个实用程序,使其他人能够异步等待您的操作。

您的操作本身需要已经是异步的。例如,如果它是在一个旧的范式中,比如BeginXXX/EndXXX。

TaskCompletionSource主要用于将不同类型的异步编程转换为基于任务的异步编程。