await Task.Delay(1000)导致task退出

ilikeff8 2021-03-30 04:41:35
Task task = Task.Factory.StartNew(async () =>
{
while (true)
{
await Task.Delay( 1000);
}
}

Task.WaitAll(new Task[] { task });

结果运行到await Task.Delay( 1000);直接跳出了while,导致 Task.WaitAll完成了,这是怎么回事,
await Task.Delay( 1000); 改成Thread.Sleep(1000)就正常了
...全文
1188 13 打赏 收藏 举报
写回复
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
正怒月神 2021-04-13
引用 9 楼 以专业开发人员为伍 的回复:
另外,通常应该使用 Task.Run 产生一个“真实代理”Task,而不是一个假代理Task。如果你写
            using System;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            test();
            Console.WriteLine("按任意键结束........");
            Console.ReadKey();
        }

        private static async void test()
        {
            var task = Task.Factory.StartNew(async () =>
            {
                while (true)
                {
                    await Task.Delay(1000);
                    Console.Write(".");
                }
            });
            await Task.WhenAll(task);
            Console.WriteLine("完成");
        }
    }
}

这个时候 task显然是完成了,因为它只代理委托返回值也就是内部那个 Task,而不监视这个 Task 是否真正完成。 而你使用 Task.Run,它代理的是内部的Task的内部的返回void,是监视真正的过程。
听君一席话,胜读十年书。
  • 打赏
  • 举报
回复
ilikeff8 2021-04-13
引用 9 楼 以专业开发人员为伍 的回复:
另外,通常应该使用 Task.Run 产生一个“真实代理”Task,而不是一个假代理Task。如果你写
            using System;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            test();
            Console.WriteLine("按任意键结束........");
            Console.ReadKey();
        }

        private static async void test()
        {
            var task = Task.Factory.StartNew(async () =>
            {
                while (true)
                {
                    await Task.Delay(1000);
                    Console.Write(".");
                }
            });
            await Task.WhenAll(task);
            Console.WriteLine("完成");
        }
    }
}

这个时候 task显然是完成了,因为它只代理委托返回值也就是内部那个 Task,而不监视这个 Task 是否真正完成。 而你使用 Task.Run,它代理的是内部的Task的内部的返回void,是监视真正的过程。
好吧,测试下来的确是这样, async 里await后,他会认为task已完成,而不恰当地往下执行了
  • 打赏
  • 举报
回复
ilikeff8 2021-04-13
引用 2 楼 wanghui0380 的回复:
我不敢保证你说的完成了,是真的完成了 Task.WaitAll(new Task[] { task }); var b=1;//加一句,断点加这里,如果你说能运行到这里,我们才认为他是真完成了
是完成了,我这个是一个.net5写的控制台测试程序,没几行代码,就是要让他后台一直执行几个task,为了防止控制台退出,但又不能readkey死等,会阻塞task,于是这么写了,一直等着所有任务完成,但任务里面实际上可以认为是死循环一直在接受和处理数据,在做间隔的时候,sleep没事,但await task.delay ,当然要加async task,然后直接waitall会判断 任务结束,是不是必须用sleep阻塞主线程
  • 打赏
  • 举报
回复
我想再强调一遍的是,“永远都不要使用 WaitXXXX”之类的阻塞式的方法。要使用真正异步编程思维。
  • 打赏
  • 举报
回复
另外,通常应该使用 Task.Run 产生一个“真实代理”Task,而不是一个假代理Task。如果你写
            using System;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            test();
            Console.WriteLine("按任意键结束........");
            Console.ReadKey();
        }

        private static async void test()
        {
            var task = Task.Factory.StartNew(async () =>
            {
                while (true)
                {
                    await Task.Delay(1000);
                    Console.Write(".");
                }
            });
            await Task.WhenAll(task);
            Console.WriteLine("完成");
        }
    }
}

这个时候 task显然是完成了,因为它只代理委托返回值也就是内部那个 Task,而不监视这个 Task 是否真正完成。 而你使用 Task.Run,它代理的是内部的Task的内部的返回void,是监视真正的过程。
  • 打赏
  • 举报
回复
不要使用任何阻塞式的 WaitXXX 之类的方法,应该使用异步方法来代替。例如:
using System;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            test();
            Console.WriteLine("按任意键结束........");
            Console.ReadKey();
        }

        private static async void test()
        {
            var task = Task.Run(async () =>
            {
                while (true)
                {
                    await Task.Delay(1000);
                    Console.Write(".");
                }
            });
            await Task.WhenAll(task);
        }
    }
}
  • 打赏
  • 举报
回复
socg 2021-04-02
Delay是异步的,进程不会被堵塞,还会继续运行,你输出结果前,应等待它执行完毕
  • 打赏
  • 举报
回复
确实挺奇怪,这个task状态直接变为rantocompletion了
  • 打赏
  • 举报
回复
wanghui0380 2021-03-31
你把他变成Task.run 也能解决问题 Task task = Task.Run(async () => { while (true) { await Task.Delay(1000); } }); 所以你的问题就可以简单变成,task.Factory 和task.run 有啥不同
  • 打赏
  • 举报
回复
wanghui0380 2021-03-31
Task.Factory.StartNew 不会保留同步上下文 如果变成方法 async task test() { while (true) { await Task.Delay( 1000); } } 就可以,因为他保留同步上下文
  • 打赏
  • 举报
回复
wtnu200 2021-03-31
Task.Delay( 1000)你可以理解为定时任务,定为1秒后执行,并不会阻塞,所以会往下面继续执行,变成while在1秒后执行 而Thread.Sleep是会阻塞的
  • 打赏
  • 举报
回复
wanghui0380 2021-03-31
我不敢保证你说的完成了,是真的完成了 Task.WaitAll(new Task[] { task }); var b=1;//加一句,断点加这里,如果你说能运行到这里,我们才认为他是真完成了
  • 打赏
  • 举报
回复
Bridge_go 2021-03-31
你这怎么也不会跳出while吧,代码就这样的???
  • 打赏
  • 举报
回复
发帖
C#

10.8w+

社区成员

.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
帖子事件
创建了帖子
2021-03-30 04:41
社区公告

让您成为最强悍的C#开发者