安全地暂停线程
Pausing a thread safely
我想知道如果我想在每次迭代时将线程暂停一段定义的时间是否有任何问题(我是 运行 一个连续循环)。
我的第一选择是使用 Task.Delay
但我不知道是否可以 issues.Should 我只是选择 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);
}
}
}
上述方法的缺点是什么?
P.S:此线程 运行 与 Windows Forms
应用程序(线程)
在这种情况下,您应该使用 Task.Delay
,因为 Thread.Sleep
会将 .NET 线程池中的线程发送到睡眠状态,而这很可能不是您想要的。您还将较低级别 Thread
与较高级别 Task
混合在一起。您不需要启动新线程。只调用 UpdateAsync()
而不调用 Wait()
或类似的就足够了。
当你想阻塞当前线程时使用Thread.Sleep
。
当您希望在不阻塞当前线程的情况下进行逻辑延迟时,请使用 Task.Delay
。
Source
我更喜欢用 Thread.Sleep
处理此类情况,因为它的级别较低,在我脑海中更有效,但这只是个人问题。
您传递给 Thread
的构造函数的 ThreadStart
委托存在潜在问题,它被定义为 public delegate void ThreadStart()
。您为其提供 async void
lambda 的事实使其成为一个即发即弃的调用。也就是说,它是异步的,但它不会 return 一个 Task
来观察结果或异常。
您的新线程很可能会在其中的执行流到达第一个 await something
、await Task.Delay
或其他任何内容时立即结束。因此,从技术上讲,您不会在此处暂停线程。之后的逻辑执行 await
将在随机线程池线程上继续,该线程很可能与您最初创建的线程不同。
你最好只使用 Task.Run
而不是 new Thread
。前者有 an override for async Task
lambdas, which you should normally be using instead of async void
anyway. Thus, you could pass your UpdateAsync
directly to Task.Run
and have the proper exception propagation logic 用于异步方法。
如果出于某种原因您仍想坚持使用 new Thread
并向其传递 async void
lambda,请确保观察 UpdateAsync
抛出的所有异常。否则,它们将被抛出 "out-of-band" 在随机池线程上,请参阅上面的 link 了解更多详细信息。还要注意,创建一个新线程(然后几乎立即结束它)是一个相当昂贵的运行时操作。 OTOH,当使用 Task.Run
时,您通常只是 borrow/return 一个现有线程 from/to 线程池,这要快得多。
就是说,在这种特殊情况下,您也可以只使用 Thread.Sleep
而不是 async
方法和 Task.Delay
,以避免不得不处理异步和线程切换全部。这是一个客户端 WinForms 应用程序,您通常不关心(在合理程度上)缩放,即繁忙或阻塞线程的数量。
我想知道如果我想在每次迭代时将线程暂停一段定义的时间是否有任何问题(我是 运行 一个连续循环)。
我的第一选择是使用 Task.Delay
但我不知道是否可以 issues.Should 我只是选择 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);
}
}
}
上述方法的缺点是什么?
P.S:此线程 运行 与 Windows Forms
应用程序(线程)
在这种情况下,您应该使用 Task.Delay
,因为 Thread.Sleep
会将 .NET 线程池中的线程发送到睡眠状态,而这很可能不是您想要的。您还将较低级别 Thread
与较高级别 Task
混合在一起。您不需要启动新线程。只调用 UpdateAsync()
而不调用 Wait()
或类似的就足够了。
当你想阻塞当前线程时使用Thread.Sleep
。
当您希望在不阻塞当前线程的情况下进行逻辑延迟时,请使用 Task.Delay
。
Source
我更喜欢用 Thread.Sleep
处理此类情况,因为它的级别较低,在我脑海中更有效,但这只是个人问题。
您传递给 Thread
的构造函数的 ThreadStart
委托存在潜在问题,它被定义为 public delegate void ThreadStart()
。您为其提供 async void
lambda 的事实使其成为一个即发即弃的调用。也就是说,它是异步的,但它不会 return 一个 Task
来观察结果或异常。
您的新线程很可能会在其中的执行流到达第一个 await something
、await Task.Delay
或其他任何内容时立即结束。因此,从技术上讲,您不会在此处暂停线程。之后的逻辑执行 await
将在随机线程池线程上继续,该线程很可能与您最初创建的线程不同。
你最好只使用 Task.Run
而不是 new Thread
。前者有 an override for async Task
lambdas, which you should normally be using instead of async void
anyway. Thus, you could pass your UpdateAsync
directly to Task.Run
and have the proper exception propagation logic 用于异步方法。
如果出于某种原因您仍想坚持使用 new Thread
并向其传递 async void
lambda,请确保观察 UpdateAsync
抛出的所有异常。否则,它们将被抛出 "out-of-band" 在随机池线程上,请参阅上面的 link 了解更多详细信息。还要注意,创建一个新线程(然后几乎立即结束它)是一个相当昂贵的运行时操作。 OTOH,当使用 Task.Run
时,您通常只是 borrow/return 一个现有线程 from/to 线程池,这要快得多。
就是说,在这种特殊情况下,您也可以只使用 Thread.Sleep
而不是 async
方法和 Task.Delay
,以避免不得不处理异步和线程切换全部。这是一个客户端 WinForms 应用程序,您通常不关心(在合理程度上)缩放,即繁忙或阻塞线程的数量。