任何人都可以解释使用Task.Run或不使用async的区别,并等待下面的代码,例如await Task.Run(async ()=>...)
?
public class AsyncRun
{
public void Entry()
{
Test4().Wait();
}
private async Task Test4()
{
Console.WriteLine($"1 {DateTime.Now}");
await Task.Run(async () => await Get());
Console.WriteLine($"2 {DateTime.Now}");
Console.Read();
//1 23 / 05 / 2020 07:52:42
//Get 1 23 / 05 / 2020 07:52:42
//Get 2 23 / 05 / 2020 07:52:43
//2 23 / 05 / 2020 07:52:43
}
private Task Test3()
{
Console.WriteLine($"1 {DateTime.Now}");
Task.Run(async ()=> await Get());
Console.WriteLine($"2 {DateTime.Now}");
Console.Read();
return Task.CompletedTask;
//1 23 / 05 / 2020 07:47:24
//2 23 / 05 / 2020 07:47:24
//Get 1 23 / 05 / 2020 07:47:24
//Get 2 23 / 05 / 2020 07:47:25
}
private async Task Test2()
{
Console.WriteLine($"1 {DateTime.Now}");
await Task.Run(Get);
Console.WriteLine($"2 {DateTime.Now}");
Console.Read();
//1 23 / 05 / 2020 07:43:24
//Get 1 23 / 05 / 2020 07:43:24
//Get 2 23 / 05 / 2020 07:43:25
//2 23 / 05 / 2020 07:43:25
}
private void Test1()
{
Console.WriteLine($"1 {DateTime.Now}");
Task.Run(Get);
Console.WriteLine($"2 {DateTime.Now}");
Console.Read();
//1 23 / 05 / 2020 07:41:09
//2 23 / 05 / 2020 07:41:09
//Get 1 23 / 05 / 2020 07:41:09
//Get 2 23 / 05 / 2020 07:41:10
}
private Task Get()
{
Console.WriteLine($"Get 1 {DateTime.Now}");
Thread.Sleep(1000);
Console.WriteLine($"Get 2 {DateTime.Now}");
return Task.CompletedTask;
}
}
答案 0 :(得分:2)
差异显示在您的Console.WriteLine
的输出中。
使用await Task.Run
时,您正在等待运行的任务完成,然后继续执行代码,因此将获得以下日志:
// 1 23 / 05 / 2020 07:52:42
// Get 1 23 / 05 / 2020 07:52:42
// Get 2 23 / 05 / 2020 07:52:43
// 2 23 / 05 / 2020 07:52:43
当您不等待刚刚运行的任务时,就好像您正在运行它并“忘记”它一样。这意味着您的代码将继续执行,并且您运行的任务将在其他地方执行,因此日志为:
// 1 23 / 05 / 2020 07:47:24
// 2 23 / 05 / 2020 07:47:24
// ^ Your test code finished executing, without waiting for the Get task
// Get 1 23 / 05 / 2020 07:47:24
// Get 2 23 / 05 / 2020 07:47:25
此外,await Task.Run(async () => await Get())
之间没有区别
和await Task.Run(Get)
的实际情况。唯一的区别是,在第一个中,您正在创建另一个异步lambda函数,以在您的Task
方法已经是Get
的情况下生成一个Task
,因此您可以直接使用它。
答案 1 :(得分:0)
一般说明
控制台不是以任何方式,形状或形式学习测试多任务处理的好环境。 MT的一大问题是MT能够保持应用程序正常运行,而又不会阻塞延续代码。在控制台中,我们必须手动执行此操作。 GUI是正确的环境,因为它们是偶然发生的。 EventQueue使应用程序保持活动状态,同时仍允许发生I / O。
Thread.Sleep()
不应在Get中使用。您应该改用更不可知的Task.Delay(1000)
。在这里使用Thread类将导致不必要的副作用,甚至破坏我们首先等待的原因。
在没有睡眠的GUI中重试一次,因为它将为您带来更有意义的结果。
什么是任务
任务只是一种结构,可以帮助所有形式的多任务处理。它与运行方式“无关”。 Get()
可以使用ThreadPools异步执行。异步使用async和await。只需调用RunSynchronously()
即可同步。或者通过从您手动启动的线程中调用RunSynchronously()
进行异步。大概还有其他几种方式,我不记得了。
不同类型的多任务处理
多线程可用于实现多任务。从技术上讲,我们只需要具有CPU限制工作的多线程,但是在最长的时间里,它通常是实现MT的最方便的方法,因此我们倾向于使用它。很多。尤其是在不必要的情况下。
即使完全理解我们为什么这么做,我认为我们过度使用到滥用基于线程的多任务处理。特别是对于GUI,Multithreading causes some issues。不过,这是更简单的方法。因此,很多事情仍然为基于线程的多任务处理而设计。
直到最近,我们才获得异步并等待替代。 async
和await
是一种多任务处理方式,无需还原到Mutlthreading。我们一直有并且仍然可以选择自己做这两个工作。但是,这需要大量代码,并且容易出错。两者很容易,并且在编译器和运行时之间可以可靠地解决。所以只有现在,我们才开始回到无线程多任务的形式。
Task.Run
:
“将指定的工作排队以在ThreadPool上运行,并返回该工作的任务或任务句柄。” -https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run
因此,Run执行一项任务,并通过ThreadPool(基于Thread的muttiasking的一种形式)执行该任务。