Выполнить задачу в новом фоновом потоке - PullRequest
0 голосов
/ 28 мая 2019

Я знаю, что есть миллион вопросов по этому поводу, и я пытаюсь найти их решение, но оно, похоже, не работает так, как я ожидал.

Со следующим кодом:

await Task.Run(() => { Thread.Sleep(5000); Console.WriteLine("I'm running after Thread.Sleep"); });
Console.WriteLine("I'm running after Task.Run");

Я получаю вывод:

[ 5 seconds elapses ]
I'm running after Thread.Sleep
I'm running after Task.Run

Это тот же вывод, который я получил бы без использования Task.Run

Что мне нужно, это вывод:

I'm running after Task.Run
[ 5 seconds elapses ]
I'm running after Thread.Sleep

Гдевыполнение «родительского» потока продолжается, а долгосрочное задание выполняется «в фоновом режиме» таким образом, чтобы это не влияло на «родительский» поток.

Ответы [ 3 ]

4 голосов
/ 28 мая 2019

Как уже упоминалось, вам нужно удалить await. Однако , что превращает его в задачу fire-and-Forgot , которая, если приведенный выше код окажется, скажем, в консольном приложении Main, тогда ваш процесс может завершиться до выполнения задачизавершено.

Хорошо:

 // C# 7
 static async void Main(string[] args) // <--- note `async` signature
 {
     await Task.Run(() => { Thread.Sleep(5000); Console.WriteLine("I'm running 
                 after Thread.Sleep"); });
     Console.WriteLine("I'm running after Task.Run");
 }

Плохо: - задание "забей и забудь", которое не await ed

 static void Main(string[] args)
 {
     Task.Run(() => { Thread.Sleep(5000); Console.WriteLine("Spider Man: I don't wan't to go!"); });  // POOF!! 

     Console.WriteLine("I'm running after Task.Run");

     // sorry Spidy, you're dead
 }

Так что вы можете вообще не видеть I'm running after Thread.Sleep, даже если у вас есть Thread.Sleep().(кстати, вы должны использовать Task.Delay()).Вы могли бы смягчить его с помощью Console.ReadKey(), но это могло бы нанести ущерб цели.

Задачи "забей и забудь" имеют свое применение и могут использоваться достаточно безопасно в других типах длительных приложения, такие как WinForms, но люди обычно не запускают Задачи в точке входа в процесс, поэтому задачи обычно выполняются до завершения без какого-либо досрочного завершения процесса.Тем не менее, как правило, рекомендуется использовать await там, где вы можете, чтобы не выстрелить себе в ногу.

Кроме того, ваши требования к желанию вещей в определенном порядке демонстрируют неправильное понимание того, какasync/await работает.

1 голос
/ 28 мая 2019

При работе с await нужно помнить, что ваш код ожидает объектов . Эти объекты, как и любые другие объекты. В частности, они могут быть назначены локальным переменным или переменным класса.

Итак, этот код:

await Task.Run(() => { Thread.Sleep(5000); Console.WriteLine("I'm running after Thread.Sleep"); });
Console.WriteLine("I'm running after Task.Run");

по сути такой же, как этот код:

var task = Task.Run(() => { Thread.Sleep(5000); Console.WriteLine("I'm running after Thread.Sleep"); });
await task;
Console.WriteLine("I'm running after Task.Run");

Другими словами:

  1. Запустить задачу, запущенную в фоновом потоке.
  2. Асинхронно ожидать (await) завершения этой задачи.
  3. Дисплей "I'm running after Task.Run".

Таким образом, ожидается вывод.

Что мне нужно, так это вывод:

Я бегу за Task.Run

[5 секунд прошло]

Я бегу за Thread.Sleep

В этом случае запустите задачу, выполняющуюся в фоновом потоке, но не await, пока она не появится позже:

var task = Task.Run(() => { Thread.Sleep(5000); Console.WriteLine("I'm running after Thread.Sleep"); });
Console.WriteLine("I'm running after Task.Run");
await task;
0 голосов
/ 28 мая 2019

Если вы хотите работать асинхронно, вы должны удалить команду

        static void Main(string[] args)
        {
            Task.Run(() => { Thread.Sleep(5000); Console.WriteLine(DateTime.Now + " => I'm running after Thread.Sleep"); });
            Console.WriteLine(DateTime.Now + " => I'm running after Task.Run");
            while (true)
            {
                Thread.Sleep(500);
            }
        }

Выход 28/05/2019 09:49:58 => I'm running after Task.Run 28/05/2019 09:50:03 => I'm running after Thread.Sleep

...