在新的后台线程中执行任务

时间:2019-05-28 12:17:10

标签: c# multithreading asynchronous

我知道对此有上百万个问题,我正在尝试他们的解决方案,但它似乎并没有我期望的那样。

使用以下代码:

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 个答案:

答案 0 :(得分:4)

如上所述,您需要删除await但是将其转换为 fire-and-forget 任务,如果上述代码恰好位于控制台应用程序的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完成的即发即弃任务

 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 :(得分:1)

使用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;

答案 2 :(得分:-1)

如果要异步运行,则应删除命令

        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

相关问题