使用 Thread.Sleep() 总是不好的吗?
Is it always bad to use Thread.Sleep()?
我为 class Random
创建了一个扩展方法,它随机执行 Action
(无效委托):
public static class RandomExtension
{
private static bool _isAlive;
private static Task _executer;
public static void ExecuteRandomAsync(this Random random, int min, int max, int minDuration, Action action)
{
Task outerTask = Task.Factory.StartNew(() =>
{
_isAlive = true;
_executer = Task.Factory.StartNew(() => { ExecuteRandom(min, max, action); });
Thread.Sleep(minDuration);
StopExecuter();
});
}
private static void StopExecuter()
{
_isAlive = false;
_executer.Wait();
_executer.Dispose();
_executer = null;
}
private static void ExecuteRandom(int min, int max, Action action)
{
Random random = new Random();
while (_isAlive)
{
Thread.Sleep(random.Next(min, max));
action();
}
}
}
它工作正常。
但是在此示例中使用 Thread.Sleep()
可以吗,或者您通常不应该使用 Thread.Sleep()
,会出现什么并发症?有其他选择吗?
使用 Thread.Sleep
不好吗?一般不会,如果你真的要挂起线程。但是在这种情况下你不想挂起线程,你想挂起任务.
所以在这种情况下,你应该使用:
await Task.Delay(minDuration);
这不会挂起整个线程,而只会挂起您要挂起的单个任务。同一线程上的所有其他任务可以继续 运行。
这样想。
休眠一个线程是危险的,因为不止一个任务依赖于该线程,更不用说程序的关键组件也可能这样做。
永远不要在线程上使用 sleep
是不合适的,当它们对您的程序有益时,您会想要使用它们。
由于不可预测的行为,许多人被教导不要休眠线程。这就像管理一个团队,最终你将不得不让一些人去吃午饭,只要其余的人在工作而你选择去吃午饭的人都出去了,那么你应该没事并且能够继续工作.
如果项目中有人依赖他们的存在,就不要派人去吃午饭。
Sleep
"talks" 到要挂起线程的操作系统。这是资源密集型操作,因为您的线程无论如何都会使用 RAM(尽管它不需要处理时间)。
有了线程池,你可以使用线程的资源(f.e.RAM)来处理一些其他的小任务。为此,Windows 允许您将线程 睡眠 置于特殊的可警报状态,因此它可能会被唤醒并暂时使用。
因此 Task.Delay
让您将线程置于可提醒的睡眠状态,因此让您可以使用这些线程的资源,除非您不需要它们。
我会使用 Task.Delay
而不是 Thread.Sleep
的一个原因是您可以将 CancellationToken
传递给它。如果用户想要 StopExecutor
并且随机收到的持续时间跨度很长,那么您最终会阻塞很长时间。另一方面,在 Task.Delay
中,您可以取消操作,它会收到取消通知。
我认为您选择的设计还有其他问题。 Random
class 并不真正 适合 作为任务调度程序。我会发现找到 ExecuteRandomAsync
有点奇怪,因为它通常不会随机执行,而是每隔 X 分钟执行一些任意 Action
。
相反,我会换一种方式来解决这个问题。在保留您已经创建的大部分内部结构的同时,将它们放在不同的 class.
中
public class ActionInvoker
{
private readonly Action _actionToInvoke;
public ActionInvoker(Action actionToInvoke)
{
_actionToInvoke = actionToInvoke;
_cancellationTokenSource = new CancellationTokenSource();
}
private readonly CancellationTokenSource _cancellationTokenSource;
private Task _executer;
public void Start(int min, int max, int minDuration)
{
if (_executer != null)
{
return;
}
_executer = Task.Factory.StartNew(
async () => await ExecuteRandomAsync(min, max, _actionToInvoke),
_cancellationTokenSource.Token, TaskCreationOptions.LongRunning,
TaskScheduler.Default)
.Unwrap();
}
private void Stop()
{
try
{
_cancellationTokenSource.Cancel();
}
catch (OperationCanceledException e)
{
// Log the cancellation.
}
}
private async Task ExecuteRandomAsync(int min, int max, Action action)
{
Random random = new Random();
while (!_cancellationTokenSource.IsCancellationRequested)
{
await Task.Delay(random.Next(min, max), _cancellationTokenSource.Token);
action();
}
}
}
全部回答正确,补充一点实际的看法:
当您有一个远程非实时组件要测试时(例如,搜索引擎),您需要在再次引用它进行断言之前让它有时间进入它的新状态。换句话说,您想暂停测试一段时间。由于测试本身的性能无关紧要(请区分 test 的性能和 component 的性能),有时您更愿意保留您的 code(测试的)尽可能简单直接,您甚至可以避免异步代码的最小复杂性。你当然可以开始一个新的测试而不是等待你的组件(这是 await Task.Delay()
和 Thread.Sleep()
之间的区别),但前提是你不急于这样做。
我为 class Random
创建了一个扩展方法,它随机执行 Action
(无效委托):
public static class RandomExtension
{
private static bool _isAlive;
private static Task _executer;
public static void ExecuteRandomAsync(this Random random, int min, int max, int minDuration, Action action)
{
Task outerTask = Task.Factory.StartNew(() =>
{
_isAlive = true;
_executer = Task.Factory.StartNew(() => { ExecuteRandom(min, max, action); });
Thread.Sleep(minDuration);
StopExecuter();
});
}
private static void StopExecuter()
{
_isAlive = false;
_executer.Wait();
_executer.Dispose();
_executer = null;
}
private static void ExecuteRandom(int min, int max, Action action)
{
Random random = new Random();
while (_isAlive)
{
Thread.Sleep(random.Next(min, max));
action();
}
}
}
它工作正常。
但是在此示例中使用 Thread.Sleep()
可以吗,或者您通常不应该使用 Thread.Sleep()
,会出现什么并发症?有其他选择吗?
使用 Thread.Sleep
不好吗?一般不会,如果你真的要挂起线程。但是在这种情况下你不想挂起线程,你想挂起任务.
所以在这种情况下,你应该使用:
await Task.Delay(minDuration);
这不会挂起整个线程,而只会挂起您要挂起的单个任务。同一线程上的所有其他任务可以继续 运行。
这样想。
休眠一个线程是危险的,因为不止一个任务依赖于该线程,更不用说程序的关键组件也可能这样做。
永远不要在线程上使用 sleep
是不合适的,当它们对您的程序有益时,您会想要使用它们。
由于不可预测的行为,许多人被教导不要休眠线程。这就像管理一个团队,最终你将不得不让一些人去吃午饭,只要其余的人在工作而你选择去吃午饭的人都出去了,那么你应该没事并且能够继续工作.
如果项目中有人依赖他们的存在,就不要派人去吃午饭。
Sleep
"talks" 到要挂起线程的操作系统。这是资源密集型操作,因为您的线程无论如何都会使用 RAM(尽管它不需要处理时间)。
有了线程池,你可以使用线程的资源(f.e.RAM)来处理一些其他的小任务。为此,Windows 允许您将线程 睡眠 置于特殊的可警报状态,因此它可能会被唤醒并暂时使用。
因此 Task.Delay
让您将线程置于可提醒的睡眠状态,因此让您可以使用这些线程的资源,除非您不需要它们。
我会使用 Task.Delay
而不是 Thread.Sleep
的一个原因是您可以将 CancellationToken
传递给它。如果用户想要 StopExecutor
并且随机收到的持续时间跨度很长,那么您最终会阻塞很长时间。另一方面,在 Task.Delay
中,您可以取消操作,它会收到取消通知。
我认为您选择的设计还有其他问题。 Random
class 并不真正 适合 作为任务调度程序。我会发现找到 ExecuteRandomAsync
有点奇怪,因为它通常不会随机执行,而是每隔 X 分钟执行一些任意 Action
。
相反,我会换一种方式来解决这个问题。在保留您已经创建的大部分内部结构的同时,将它们放在不同的 class.
中public class ActionInvoker
{
private readonly Action _actionToInvoke;
public ActionInvoker(Action actionToInvoke)
{
_actionToInvoke = actionToInvoke;
_cancellationTokenSource = new CancellationTokenSource();
}
private readonly CancellationTokenSource _cancellationTokenSource;
private Task _executer;
public void Start(int min, int max, int minDuration)
{
if (_executer != null)
{
return;
}
_executer = Task.Factory.StartNew(
async () => await ExecuteRandomAsync(min, max, _actionToInvoke),
_cancellationTokenSource.Token, TaskCreationOptions.LongRunning,
TaskScheduler.Default)
.Unwrap();
}
private void Stop()
{
try
{
_cancellationTokenSource.Cancel();
}
catch (OperationCanceledException e)
{
// Log the cancellation.
}
}
private async Task ExecuteRandomAsync(int min, int max, Action action)
{
Random random = new Random();
while (!_cancellationTokenSource.IsCancellationRequested)
{
await Task.Delay(random.Next(min, max), _cancellationTokenSource.Token);
action();
}
}
}
全部回答正确,补充一点实际的看法:
当您有一个远程非实时组件要测试时(例如,搜索引擎),您需要在再次引用它进行断言之前让它有时间进入它的新状态。换句话说,您想暂停测试一段时间。由于测试本身的性能无关紧要(请区分 test 的性能和 component 的性能),有时您更愿意保留您的 code(测试的)尽可能简单直接,您甚至可以避免异步代码的最小复杂性。你当然可以开始一个新的测试而不是等待你的组件(这是 await Task.Delay()
和 Thread.Sleep()
之间的区别),但前提是你不急于这样做。