Как изменить планировщик Task.Run? - PullRequest
0 голосов
/ 27 марта 2019

Мне нужно выполнить несколько задач, которые необходимо запустить с использованием определенного планировщика, поскольку в противном случае они не будут работать, поскольку объекты, которые они создают, могут быть только из определенного потока.

Использование 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();
    }
}

Ответы [ 2 ]

1 голос
/ 01 апреля 2019

То, что вы хотите, это TaskFactory. Просто создайте один с вашим желаемым TaskScheduler. Кроме того, вы, как правило, не хотите использовать настройки параметров по умолчанию. Предполагая, что вы используете задачи с await, вы обычно хотите по крайней мере DenyChildAttach:

var factory = new TaskFactory(CancellationToken.None,
    TaskCreationOptions.DenyChildAttach,
    TaskContinuationOptions.DenyChildAttach | TaskContinuationOptions.ExecuteSynchronously,
    scheduler);

После создания (один раз) вы можете использовать factory.StartNew для постановки в очередь без необходимости каждый раз передавать все параметры.

1 голос
/ 27 марта 2019

Вы просто не можете этого сделать.К тому времени, как вы получите Task от Task.Run, задача уже запланирована в планировщике по умолчанию и, возможно, уже выполняется.Если вы хотите использовать собственный планировщик, не используйте Task.Run.Либо используйте Task.Factory.StartNew, либо напишите свой собственный метод, чтобы запланировать новую задачу определенным образом.

...