我需要运行一些需要使用特定调度程序运行的任务,否则它们将失败,因为它们实例化的对象只能来自特定线程。
使用Task.Factory.StartNew
效果很好,唯一的是语法有点麻烦。
因此,我想到了编写一种扩展方法的想法,该方法可以使我保留Task.Run
的简洁语法,但可以指定除TaskScheduler.Default
之外的另一个调度程序。但是,我很难弄清楚如何编写这种扩展方法。
问题:
如果可能的话,如何更改要运行的Task.Run
的调度程序?
代码示例:
using System;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
public class NewBehaviourScript : MonoBehaviour
{
private async void Test()
{
// game objects can only be created from Unity main thread, get its scheduler
var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
// 1. syntax using factory, works but is a bit cumbersome
await Task.Factory.StartNew(
() => new GameObject("test"),
CancellationToken.None,
TaskCreationOptions.None,
scheduler
);
// 2. ideal syntax though it will fail since it'll run with the wrong scheduler
await Task.Run(() => new GameObject("test"));
// 3. ideal syntax but how to implement .Schedule method?
await Task.Run(() => new GameObject("test")).Schedule(scheduler);
}
}
扩展方法:
public static class Extensions
{
public static Task<T> Schedule<T>(this Task<T> task, TaskScheduler scheduler)
{
// how, if possible at all to write this method?
throw new NotImplementedException();
}
}
答案 0 :(得分:1)
您根本无法做到这一点。到您从Task
返回Task.Run
时,该任务已经在默认调度程序上进行了调度,并且可能已经在运行。如果要使用自定义调度程序,请不要使用Task.Run
。使用Task.Factory.StartNew
,或编写自己的方法以特定方式安排新任务。
答案 1 :(得分:1)
您想要的是TaskFactory
。只需使用所需的TaskScheduler
创建一个即可。另外,您通常不希望使用默认选项设置。假设您正在使用await
的任务,通常通常至少需要DenyChildAttach
:
var factory = new TaskFactory(CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskContinuationOptions.DenyChildAttach | TaskContinuationOptions.ExecuteSynchronously,
scheduler);
创建一次(一次)后,您可以使用factory.StartNew
将工作排队,而不必每次都传递所有参数。