安全地暂停线程

时间:2019-04-24 06:43:55

标签: c# multithreading task-parallel-library

我想知道是否要在每次迭代中将线程暂停一段定义的时间(我正在运行一个连续循环)。 我的首选是使用Task.Delay,但我不知道是否可能有任何问题。我应该只使用Thread.Sleep还是EventWaitHandle吗?

class UpdateThread {

        private  Thread thread;
        Fabric.Client client;
        public UpdateThread(Fabric.Client client) {

        }
        public void Run() {
            thread = new Thread(new ThreadStart(async()=>await UpdateAsync()));
        }
        public async Task UpdateAsync() {

            while (true) {
                await Task.Delay(Constants.REFRESH_INTERVAL);

            }

        }

    }

上述方法的缺点是什么?

PS :此线程与Windows Forms应用程序(线程)一起运行

3 个答案:

答案 0 :(得分:1)

在这种情况下,您应该使用Task.Delay,因为Thread.Sleep将从.NET ThreadPool发送一个线程进入睡眠状态,而这很可能不是您想要的。您还将混合较低级别的Thread和较高级别的Task。您不需要启动新线程。只需调用UpdateAsync()而不调用Wait()或类似的电话就足够了。

答案 1 :(得分:1)

您传递给Thread的构造函数(定义为public delegate void ThreadStart()的{​​{3}}委托存在潜在的问题。您为其提供了async void lambda的事实,使它成为一劳永逸的调用。也就是说,它是异步的,但不会返回Task来观察结果或异常。

您的新线程很可能在其内部的执行流达到第一个await something(无论是await Task.Delay还是其他)后结束。因此,从技术上讲,您不会在此处暂停线程await之后的逻辑执行将在随机线程池线程上继续,该线程池很可能与您最初创建的线程不同。

最好使用Task.Run而不是new Thread。前者有ThreadStartasync Task的lambda,您通常应该使用它而不是async void。因此,您可以将UpdateAsync直接传递给Task.Run,并让an override用于异步方法。

如果由于某些原因您仍然想坚持使用new Thread并向其传递async void lambda,请确保观察UpdateAsync引发的所有异常。否则,它们将被“带外”抛出到随机池线程中,有关更多详细信息,请参见上面的链接。还要注意,创建一个新线程(然后几乎立即终止它)是一个相当昂贵的运行时操作。 OTOH,在使用Task.Run时,通常只需要从线程池中借用/返回现有线程即可,这要快得多。

也就是说,在这种特殊情况下,您最好只使用Thread.Sleep而不是async方法和Task.Delay,以避免根本不必处理异步和线程切换。这是一个客户端WinForms应用程序,通常不需要(在合理范围内)扩展,即忙碌或阻塞线程的数量。

答案 2 :(得分:0)

要阻塞当前线程时,请使用Thread.Sleep

要在不阻塞当前线程的情况下进行逻辑延迟,请使用Task.Delay

Source

我更喜欢用Thread.Sleep处理这种情况,因为它在我脑海中的位置较低且更有效,但这只是个人原因。