private void button1_Click(object sender, EventArgs e)
{
Task<int> task = Fun3();
Task task2 = Func1();
Console.WriteLine("等待前输出");
await task;
await task2;
//Task.WaitAll(task, task2); //这种写法会阻塞主线程,导致死锁
Console.WriteLine("等待后输出");
Console.WriteLine(task.Result);
}
private static async Task Func1()
{
await Task.Run(() =>
{
Thread.Sleep(2000);
Console.WriteLine("2222");
});
}
private static async Task<int> Fun3()
{
int ret = 0;
await Task.Run(() =>
{
var result = Task.Run(async () => await Fun4());
if (result.Result > 0)
{
Console.WriteLine("正确流程");
}
else
{
Console.WriteLine("错误流程");
ret = 1;
}
});
return ret;
}
private static async Task<int> Fun4()
{
int ret = 0;
await Task.Run(() =>
{
if (3 > 2)
ret = 1;
});
return ret;
}
Fun1和Func3是2个单独的任务,可以异步执行。Fun3执行时需依赖Fun4的结果,才能执行后续。上边的写法看起来功能可以实现,不过感觉写法有点奇怪,之前用的比较少,请熟悉的人帮忙看下。如果写法有问题,需要怎么修改?
该回答引用GPTᴼᴾᴱᴺᴬᴵ
这段代码的使用 async 和 await 是正确的,可以实现异步执行任务的效果。不过有几点需要注意:
1.Func1 方法的实现没有必要使用 Task.Run,因为 Task.Run 会把代码放到线程池中执行,而 Thread.Sleep 不会占用线程。所以可以直接写成:
private static async Task Func1()
{
await Task.Delay(2000);
Console.WriteLine("2222");
}
2.Fun3 方法中有一个奇怪的写法:
var result = Task.Run(async () => await Fun4());
if (result.Result > 0)
这里使用 Task.Run 创建了一个新的 Task,并等待其执行完毕,这里的 Task 实际上就是 Fun4 方法的返回值。但是这里使用了 result.Result,这意味着要等待这个 Task 执行完毕并且返回结果才能继续执行后面的代码。这种写法有可能会导致死锁,因为在 UI 线程中等待一个需要执行的任务完成时,如果这个任务需要在 UI 线程中执行,那么就会导致死锁。
所以,正确的写法应该是:
int result = await Fun4();
if (result > 0)
直接使用 await 等待 Fun4 方法的返回值即可,不需要创建额外的 Task。
3.await 后面的任务有可能会抛出异常,需要使用 try-catch 捕获并处理异常。
Fun3 里直接写 await Fun4 即可
请理解await/async的含义,这个叫异步IO,不是啥某园子争论几个月都争论不清的啥子task,线程
异步IO和Task本身根本就不在一个讨论级别。不是要await 就要搞个task.run
所以你在Fun3里直接写await Fun4,不需要在Fun3里用个Task.run在套
另外提醒一下:
到底啥叫异步IO,异步IO本质上于task,线程没有必然联系
异步IO本质上的核心逻辑是异步获取执行结果,其实他是回调。只不过官方用个语法糖级别的玩意把写法简化了。
以前有也有ASynCall的写法,也有异步invoke的写法,只是代码复杂推广很多年也没有啥程序员玩熟了(而且回调还有回调地狱,代码逻辑乱)
现在这个await/async和以前的AsyncCall回调委托没有本质区别,只是语法糖罢了。(语法糖的含义就是本质上他没区别,就算用以前的代码也一样实现,不过是糖好吃)
所以回到以前的逻辑,你就知道你的Fun3其实不需要在套Task.run
回到以前的逻辑,假设你调用一个Fun4,至于Fun4开不开线程是Fun4的事情,他跟Fun3没有关系
如果fun4执行完毕,他执行一个AsyncCall回调Fun3,所以你看到了Fun3开不开Task.Run并不是重点,重点是他是一个异步IO
你套了太多层了
既然f4必须执行完才能执行f3,那你f4和f3顺序执行就好了,为什么要异步
你这异步完又同步,不够折腾的
最外层调用这几个函数的地方为了避免阻塞写个异步就行了,不要每个函数都异步
你这写的挺乱的,看你需求就是按下button时候不阻塞主线程就行了。一个async足矣
private async void button1_Click(object sender, EventArgs e) {
Console.WriteLine("等待前输出");
var task = Fun3();//异步
Func1();//异步
Console.WriteLine("等待后输出");
//.Result等待Fun3执行完成,还是会阻塞主线程。
//用了.Result就别想着异步了,建议把button也改成async,就不会阻塞主线程
//Console.WriteLine(task.Result);
await Task.Run(()=> Console.WriteLine(task.Result));
}
private static async Task Func1() {
await Task.Run(() => {
Thread.Sleep(2000);
Console.WriteLine("2222");
});
}
private static async Task<int> Fun3() {
int ret = 0;
await Task.Run(() => {
var result = Fun4();//Fun4没有异步的必要就别写成async了
if (result > 0) {
Console.WriteLine("正确流程");
} else {
Console.WriteLine("错误流程");
ret = 1;
}
});
return ret;
}
private static int Fun4() {
int ret = 0;
if (3 > 2)
ret = 1;
return ret;
}