Как я могу заставить ждать продолжить в том же потоке?
await
не гарантирует продолжения той же задачи для порожденных задач:
private void TestButton_Click(object sender, RoutedEventArgs e)
{
Task.Run(async () =>
{
Debug.WriteLine("running on task " + Task.CurrentId);
await Task.Delay(TimeSpan.FromMilliseconds(100));
Debug.WriteLine("running on task " + Task.CurrentId);
});
}
Выход этого:
running on task 1
running on task
Таким образом, мы видим, что не только выполнение переместилось в другую задачу, но и в поток пользовательского интерфейса. Как я могу создать отдельную задачу и заставить ждать всегда продолжать эту задачу? Долгосрочные задачи также не делают этого.
Я видел несколько реализаций SynchronizationContext, но до сих пор ни одна из них не работала, в данном случае, потому что он использует потоки и System.Threading.Thread недоступен для uwp.
2 ответа
Таким образом, мы видим, что не только выполнение переместилось в другую задачу, но и в поток пользовательского интерфейса.
Нет, это не в потоке пользовательского интерфейса. Это просто технически не на задачу, либо. Я объясняю, почему это происходит в моем блоге на Task.CurrentId
в async
методы.
Как я могу создать отдельную задачу и заставить ждать всегда продолжать эту задачу? Долгосрочные задачи также не делают этого.
Вы на правильном пути: вам нужен кастом SynchronizationContext
(или обычай TaskScheduler
).
Я видел несколько реализаций SynchronizationContext, но до сих пор ни одна из них не работала, в данном случае, потому что он использует потоки и System.Threading.Thread недоступен для uwp.
Попробуйте мой. Должно работать на UWP 10.0.
Не использовать Task.Run
просто сделайте обработчик событий асинхронным
private async void TestButton_Click(object sender, RoutedEventArgs e)
{
await dedicated();
}
private async Task dedicated()
{
Console.WriteLine("running on task {0}", Task.CurrentId.HasValue ? Task.CurrentId.ToString() : "null");
await Task.Delay(TimeSpan.FromMilliseconds(100));
Console.WriteLine("running on task {0}", Task.CurrentId.HasValue ? Task.CurrentId.ToString() : "null");
}
Узнайте больше о Task.CurrentId
в асинхронных методах здесь:
Так
Task.CurrentId
возвращаетсяnull
потому что нет задачи на самом деле выполнения.
Ответить на комментарии
- "Он по-прежнему работает в потоке пользовательского интерфейса, а не порождается задачей".
Случай с потоком пула потоков включен в ссылку. В частности, посмотрите на этот пример
static void Main(string[] args)
{
var task = Task.Run(() => MainAsync());
task.Wait();
taskRun = task.Id.ToString();
Console.WriteLine(beforeYield + "," + afterYield + "," + taskRun);
Console.ReadKey();
}
static async Task MainAsync()
{
beforeYield = Task.CurrentId.HasValue ? Task.CurrentId.ToString() : "null";
await Task.Yield();
afterYield = Task.CurrentId.HasValue ? Task.CurrentId.ToString() : "null";
}
Опять же, разъяснение
null
вступает в игру, потому чтоasync
Метод сначала выполняется как фактическая задача в пуле потоков. Однако после егоawait
, он возобновляется как обычный делегат в пуле потоков (не фактическая задача).
- "Мой вопрос заключается в том, как остановить это от этого"
Это деталь реализации async
позвоните, я могу только процитировать ссылку снова:
Вполне вероятно, что такое поведение является просто результатом самой простой и эффективной реализации.
Так что вы не можете и не должны мешать ему делать это, насколько это действительно async
вызов обеспокоен.
То, что вы описываете как ожидаемое поведение, вместо этого эквивалентно Task.Run
без await
private void expected()
{
Task task = Task.Run(() =>
{
Console.WriteLine("Before - running on task {0} {1}",
Task.CurrentId.HasValue ? Task.CurrentId.ToString() : "null",
Environment.CurrentManagedThreadId);
Task.Delay(TimeSpan.FromMilliseconds(100)).Wait();
Console.WriteLine("After - running on task {0} {1}",
Task.CurrentId.HasValue ? Task.CurrentId.ToString() : "null",
Environment.CurrentManagedThreadId);
});
}
Или вложенный Task.Run
private void expected()
{
Task task = Task.Run(() =>
{
Console.WriteLine("Before - running on task {0} {1}",
Task.CurrentId.HasValue ? Task.CurrentId.ToString() : "null",
Environment.CurrentManagedThreadId);
var inner = Task.Run( async () =>
await Task.Delay(TimeSpan.FromMilliseconds(100)));
inner.Wait();
Console.WriteLine("After - running on task {0} {1}",
Task.CurrentId.HasValue ? Task.CurrentId.ToString() : "null",
Environment.CurrentManagedThreadId);
});
}
Выход
Before - running on task 312 11
After - running on task 312 11
Before - running on task 360 11
After - running on task 360 11
Before - running on task 403 15
After - running on task 403 15