Примечание: это в Unity3D
Мне нужно запустить внутреннюю задачу, используя пользовательский контекст синхронизации, например:
- внешняя задача - > по умолчанию в планировщике
- внутренняя задача -> в пользовательском планировщике с пользовательским контекстом синхронизации
Это связано с тем, что некоторые объекты во внутренней задаче могут быть созданы только в с другой стороны, я хочу, чтобы внешняя задача работала нормально, т. е. ThreadPool
или все, что Task.Run
использует.
После совет по этому вопросу:
Как запустить задачу на пользовательском TaskScheduler с помощью 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
{
}
Когда я отлаживаю, я вижу, что на фабрике изготовителя действительно есть настраиваемый планировщик с настраиваемым контекст, но на практике это не работает, однако. * 103 5 *
Вопрос:
Как мне заставить мой пользовательский планировщик использовать пользовательский контекст, из которого он был создан?
Окончательный ответ:
Я ждал метод внутри потока, в котором я хотел бы избежать работы, завернув этот материал в await Task.Run
(плюс некоторые детали, оставленные для краткости), исправил его. Теперь я могу запускать свою длинную задачу вне потока Unity, но по-прежнему делать внутри нее вызовы Unity, используя описанный выше пользовательский подход к фабрике.
т.е. она уже работала, но я не использовал ее правильно