gpt4 book ai didi

c# - 自定义 TaskFactory 不使用自定义 SynchronizationContext

转载 作者:行者123 更新时间:2023-12-04 10:12:58 30 4
gpt4 key购买 nike

注意:这是在Unity3D下

我需要使用自定义同步上下文运行内部任务,如下所示:

  • 外部任务 -> 在默认调度程序上
  • 内部任务 -> 在具有自定义同步上下文的自定义调度程序上

  • 这是因为内部任务中的某些对象只能在自定义同步上下文将发布到的特定线程上创建,另一方面,我希望外部任务正常运行,即 ThreadPool或其他 Task.Run使用。

    遵循这个问题的建议:

    How to run a Task on a custom TaskScheduler using await?

    不幸的是,这不起作用,同步上下文仍然是默认的:
    OUTER JOB: 'null'
    0
    INNER JOB: 'null' <------------- this context should not be the default one
    0, 1, 2, 3, 4,
    1
    INNER JOB: 'null'
    0, 1, 2, 3, 4,
    2
    INNER JOB: 'null'
    0, 1, 2, 3, 4,
    Done, press any key to exit

    代码:
    using System;
    using System.Threading;
    using System.Threading.Tasks;

    internal static class Program
    {
    private static TaskFactory CustomFactory { get; set; }

    private static async Task Main(string[] args)
    {
    // create a custom task factory with a custom synchronization context,
    // and make sure to restore initial context after it's been created

    var initial = SynchronizationContext.Current;

    SynchronizationContext.SetSynchronizationContext(new CustomSynchronizationContext());

    CustomFactory = new TaskFactory(
    CancellationToken.None,
    TaskCreationOptions.DenyChildAttach,
    TaskContinuationOptions.None,
    TaskScheduler.FromCurrentSynchronizationContext()
    );

    SynchronizationContext.SetSynchronizationContext(initial);


    // now do some work on initial context

    await Task.Run(async () =>
    {
    Console.WriteLine($"OUTER JOB: {GetCurrentContext()}");

    for (var i = 0; i < 3; i++)
    {
    Console.WriteLine(i);
    await Task.Delay(100);

    // now do some work on custom context
    await RunOnCustomScheduler(DoSpecialWork);
    }
    });

    Console.WriteLine("Done, press any key to exit");
    Console.ReadKey();
    }

    private static void DoSpecialWork()
    {
    Console.WriteLine($"\tINNER JOB: {GetCurrentContext()}"); // TODO wrong context

    for (var i = 0; i < 5; i++)
    {
    Thread.Sleep(250);
    Console.Write($"\t{i}, ");
    }

    Console.WriteLine();
    }

    private static Task RunOnCustomScheduler(Action action)
    {
    return CustomFactory.StartNew(action);
    }

    private static string GetCurrentContext()
    {
    return SynchronizationContext.Current?.ToString() ?? "'null'";
    }
    }

    public class CustomSynchronizationContext : SynchronizationContext
    {
    }

    当我调试时,我可以看到自定义工厂确实具有带有自定义上下文的自定义调度程序,但实际上它不起作用。

    问题:

    如何让我的自定义调度程序使用创建它的自定义上下文?

    最终答案:

    我正在等待一个我想避免在线程中工作的方法,将这些东西包装在 await Task.Run 中。 (加上为简洁起见省略了一些细节)修复了它。现在我可以在 Unity 线程之外运行我的长任务,但仍然使用上面提到的自定义工厂方法在其中进行 Unity 调用。

    即它已经在工作,但我没有正确使用它

    最佳答案

    您的 CustomSynchronizationContext确实用于运行DoSpecialWork方法。您可以通过覆盖 Post 来确认这一点。基类的方法:

    public class CustomSynchronizationContext : SynchronizationContext
    {
    public override void Post(SendOrPostCallback d, object state)
    {
    Console.WriteLine($"@Post");
    base.Post(d, state);
    }
    }

    然后再次运行你的程序,你会看到三个@Post 出现在控制台中。

    SynchronizationContext.Current 的原因是 null是因为此属性与当前线程相关联。这是 source code :
    // Get the current SynchronizationContext on the current thread
    public static SynchronizationContext Current
    {
    get
    {
    return Thread.CurrentThread.GetExecutionContextReader().SynchronizationContext ?? GetThreadLocalContext();
    }
    }

    您可以安装您的 CustomSynchronizationContext ThreadPool 的每个线程中,但不推荐这样做。这也不是必需的。在没有 SynchronizationContext.Current 的情况下异步延续正在当前 TaskScheduler 中运行,以及当前 TaskSchedulerDoSpecialWorkAsync方法是您自己使用 TaskScheduler.FromCurrentSynchronizationContext() 创建的方法。方法,与您的 CustomSynchronizationContext 相关联实例。

    关于c# - 自定义 TaskFactory 不使用自定义 SynchronizationContext,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61235015/

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