配置TaskCompletionSource的任务的延续行为 [英] Configuring the continuation behaviour of a TaskCompletionSource's Task

查看:122
本文介绍了配置TaskCompletionSource的任务的延续行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下code:

public Task SomeAsyncMethod()
{
    var tcs = new TaskCompletionSource();
    ... do something, NOT setting the TaskCompletionSource...

    return tcs.Task
}

public void Callsite1()
{
    await SomeAsyncMethod();
    Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
}

public void Callsite2()
{
    SomeAsyncMethod().ContinueWith((task) =>
    {
        Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
    });
}

在某个时间点,在SomeAsyncMethod创建的TaskCompletionSource设置在一个线程池主题:

At some point in time, the TaskCompletionSource created in SomeAsyncMethod is set on a ThreadPool Thread:

Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
tcs.SetResult();

在从TaskCompletionSource任务是等待(如Callsite1),延续上调用的setResult线程同步执行。当ContinueWith被调用(如Callsite2),继续在不同的线程异步执行。

When the Task from the TaskCompletionSource is awaited (as in Callsite1), the continuation executes synchronously on the Thread that called SetResult. When ContinueWith is called (as in Callsite2), the continuation executes asynchronously on a different thread.

这不利于调用配置计谋,如

It does not help to call configure the await, as in

public void Callsite1()
{
    await SomeAsyncMethod().ConfigureAwait(true or false);
}

和这甚至不是对这个问题的地步。由于SomeAsyncMethod的实现者,我不想通过调用的setResult调用一些潜在的未知code。我想有永远定异步的延续。我不能靠调用者正确配置的await(如果这甚至会工作)。

and this is not even the point of this question. As the implementor of SomeAsyncMethod, I do not want to call some potentially unknown code by calling SetResult. I want to have the continuation always scheduled asynchronously. And I cannot rely on the caller to configure the await properly (if that would even work).

如何才能TaskCompletionSource配置使得它的任务不执行其延续同步时,它期待已久的?

How can a TaskCompletionSource be configured such that its Task doesn't execute its continuation synchronously when it's awaited?

推荐答案

有没有办法为prevent同步任务的延续。通常情况下,这是没有问题的。

There is no way to prevent synchronous task continuations. Normally, this is not a problem.

然而,也有一些情况下,你确实需要这一点,例如,如果你在完成任务的同时持有锁定。在这种情况下,你可以 Task.Run 任务完成,因为这样的:

However, there are some situations where you do need this, e.g., if you are completing the task while holding a lock. In those cases, you can just Task.Run the task completion, as such:

// Set the result on a threadpool thread, so any synchronous continuations
//  will execute in the background.
Task.Run(() => tcs.TrySetResult(result));

// Wait for the TCS task to complete; note that the continuations
//  may not be complete.
tcs.Task.Wait();

这是一种先进的技术。这是一个例外方针唐在 T块异步 code(异步一路下跌)作为阐述了在我的博客

This is an advanced technique. It is an exception to the guideline "Don't block on async code (async all the way down)" as expounded on my blog.

这是我的 AsyncEx库的一部分,作为一个扩展方法:

It's part of my AsyncEx library, as an extension method:

public static void TrySetResultWithBackgroundContinuations<TResult>(
    this TaskCompletionSource<TResult> @this, TResult result);

该技术是首次出版由斯蒂芬Toub在他的博客

这篇关于配置TaskCompletionSource的任务的延续行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆