C# 中在没有同步上下文的情况下推迟任务执行的最佳方法

问题描述 投票:0回答:1

在 C# 中的异步方法中,我需要推迟执行(将执行返回给调用者),并在继续执行之前清除同步上下文。

语句“await Task.Delay(1).ConfigureAwait(false);”在方法开始时会这样做,但由于延迟,平均性能损失为 15 毫秒。

推迟和清除执行上下文的更好方法是检查当前执行上下文并调用 Task.Yield (它保留执行上下文,如果有)或 Task.Delay(1).ConfigureAwait(false):

public async Task Test()
{
    if (SynchronizationContext.Current is null)
    {
        await Task.Yield();
    }
    else
    {
        await Task.Delay(1).ConfigureAwait(false);
    }

    // Deferred code
}

你知道是否有更简单的方法来推迟当前任务的执行(如Task.Yield)并同时清除同步上下文?

c# yield deferred-execution
1个回答
0
投票

我不能这样做,因为 Task.Yield 和 Task.ConfigureAwait 对可等待/等待值使用不同的结构:

public async ??? TaskYieldNoSyncContext() =>
    (SynchronizationContext.Current is null)
      ? Task.Yield()
      : Task.Delay(1).ConfigureAwait(false);

public async Task Test()
{
    await TaskYieldNoSyncContext();

    // Deferred code
}

因此,我创建以下内容将ConfiguredTaskAwaitable/ConfiguredTaskAwaiter 和 YieldAwaitable/YieldAwaiter 合并到单个嵌套结构中:

具有“await”关键字所需实现的接口:

public interface ICustomAwaitable
{
    public ICustomAwaiter GetAwaiter();

    public interface ICustomAwaiter : ICriticalNotifyCompletion
    {
        public bool IsCompleted { get; }
        public void GetResult();
    }
}

ConfiguredTaskAwaitable/ConfiguredTaskAwaiter 的实现:

public struct CustomAwaitableTask : ICustomAwaitable
{
    private readonly ConfiguredTaskAwaitable _awaitable;

    public CustomAwaitableTask(ConfiguredTaskAwaitable awaitable)
    {
        _awaitable = awaitable;
    }

    public ICustomAwaitable.ICustomAwaiter GetAwaiter() { return new CustomAwaiterTask(_awaitable.GetAwaiter()); }

    public struct CustomAwaiterTask : ICustomAwaitable.ICustomAwaiter
    {
        private readonly ConfiguredTaskAwaitable.ConfiguredTaskAwaiter _awaiter;

        public CustomAwaiterTask(ConfiguredTaskAwaitable.ConfiguredTaskAwaiter awaiter)
        {
            _awaiter = awaiter;
        }

        public bool IsCompleted => _awaiter.IsCompleted;

        public void OnCompleted(Action continuation) => _awaiter.OnCompleted(continuation: continuation);

        public void UnsafeOnCompleted(Action continuation) => _awaiter.UnsafeOnCompleted(continuation: continuation);

        public void GetResult() => _awaiter.GetResult();
    }
}

YieldAwaitable/YieldAwaiter 的实现:

public struct CustomAwaitableYield : ICustomAwaitable
{
    private readonly YieldAwaitable _awaitable;

    public CustomAwaitableYield(YieldAwaitable awaitable)
    {
        _awaitable = awaitable;
    }

    public ICustomAwaitable.ICustomAwaiter GetAwaiter() { return new CustomAwaiterYield(_awaitable.GetAwaiter()); }

    public struct CustomAwaiterYield : ICustomAwaitable.ICustomAwaiter
    {
        private readonly YieldAwaitable.YieldAwaiter _awaiter;

        public CustomAwaiterYield(YieldAwaitable.YieldAwaiter awaiter)
        {
            _awaiter = awaiter;
        }

        public bool IsCompleted => _awaiter.IsCompleted;

        public void OnCompleted(Action continuation) => _awaiter.OnCompleted(continuation: continuation);

        public void UnsafeOnCompleted(Action continuation) => _awaiter.UnsafeOnCompleted(continuation: continuation);

        public void GetResult() => _awaiter.GetResult();
    }
}

以及根据当前同步上下文返回这些实现之一的静态方法:

public static ICustomAwaitable YieldNoSyncContext()
{
    if (SynchronizationContext.Current is null)
    {
        return new CustomAwaitableYield(Task.Yield());
    }
    else
    {
        return new CustomAwaitableTask(Task.Delay(1).ConfigureAwait(false));
    }
}

这样我就可以推迟任务并以最小的性能影响清除同步:

public async Task Test()
{
    await TaskYieldNoSyncContext();

    // Deferred code
}
© www.soinside.com 2019 - 2024. All rights reserved.