当前位置: 首页 > 知识库问答 >
问题:

替代使用线程。睡觉等待

姚星宇
2023-03-14

首先,我没有问与C#相同的问题-线程的替代品。睡眠?,或线程的替代品。睡在C#?。我不认为我使用它是错误的,需要一个真正的替代特定的情况。

在一次代码分析运行中,我看到了一个令人惊讶的违规行为:

线程的用法。睡眠()是设计缺陷的标志。

这一违规行为导致彼得·里奇(Peter Richie)撰写了一篇文章,阐述了为什么这构成了糟糕的设计

我们都知道线程创建是昂贵的,线程阻塞意味着池中的争用。我们还知道,每个线程都会分配一兆内存,所以它的寿命应该很短,在UI上阻塞是邪恶的,使用睡眠计时是不可靠的等等。这就引出了我的观点,如果你真的需要执行睡眠,如果不是线程,你应该使用什么。睡觉

彼得接着提到零睡眠是唯一正确使用线程的方法。睡眠有效地放弃了线程的时间片,并允许其他线程进行处理。更可怕的是,由于非托管线程的限制,这仅仅是一个错误,如果在CLR中重新实现,将产生使用线程的副作用。在应用程序中睡眠。事实上,所有关于常见不良用法的观点都是不良用法的好例子。

在使用线程的生产代码中有以下情况。睡得很好:

  • 等待操作系统放弃文件锁(发现文件锁问题,等待一秒钟,再试一次,过一会儿放弃)
  • 终止一个进程并等待它不出现在进程列表中(终止它,检查它是否未运行,等待一秒钟,检查它是否仍在运行,强制关闭它)
  • 等待复制缓冲区刷新(检查文件大小,尝试访问它,等待,检查大小是否已更改)

不使用线程。在这种情况下睡觉,我还有什么选择?紧循环往往会让事情变得更糟,我不认为这会让它的使用成为一个“设计缺陷”,尤其是因为UI上没有任何内容,只有后台线程。软件的本质就是在多线程环境中等待其他事情,外部因素会影响代码,有时你需要等待。。。

共有3个答案

柯良骏
2023-03-14

在我的一个项目中,我使用了两个线程,我在UI将thnx冻结到线程时遇到了问题。睡觉这解决了我的问题:

    public static void Sleeping(int miliseconds)
    {
        var task = Sleep(miliseconds);
        task.Wait();
    }

    public static async Task Sleep(int miliseconds)
    {
        await Task.Delay(miliseconds);
    }

编辑:

正如Darky711所建议的,更好的方法是:

Task.Delay(1000).Wait();
谭宏盛
2023-03-14

大部分都是你说的。引用“我们都知道线程创建是昂贵的,线程中的阻塞意味着池中的争用”,所以您甚至可以理解使用线程池的意义。

您也明白阻止UI线程是不好的。

再看看线程池模型:你有一个线程池,可能每个处理器一个,然后把任务传递给他们。如果其中一个线程被阻塞,又有什么意义呢?如果它现在没有工作要做,那么它应该直接进行另一项任务。

那么,直接转到你的问题“这让我想到了我的观点,如果你真的需要进行睡眠,如果不是线程睡眠,你应该使用什么?”,在一个设计良好的现代程序中,你永远不需要这样做,你只需要为后者安排一项任务。

您应该将池中的线程,就像系统中的处理器一样,视为资源,在不需要的时候应该释放给其他人。

看看你的例子,你对命令式编程范式有点太投入了。

  • 你不需要等待一个过程消失。。。我不知道你为什么需要这个,但如果你不得不等待,那是因为你需要在某个时间后完成工作,你的功能的“延续”。你应该为这个“继续”设置一个计时器

等待同步机制并不“坏”。

艾焕
2023-03-14

WaitHandle类型和派生类型为连接到操作系统的等待提供了事件驱动机制。例如,当你有一个任务

有时,基于轮询的方法是必要的,就像您在项目符号列表中给出的一些示例一样,但通常可以使用事件驱动的方法。不是那个线程。睡眠总是不好的——只是它经常被滥用。

在有外部因素影响你的代码的多线程环境中等待其他事情只是软件的本质,有时你需要等待...

等待是好的。等待投票通常不是(*)。如果有任何方法可以使用事件驱动的等待,通常应该努力使用它。

我不太清楚你问的到底是什么,所以我不会再详细说明了。如果你留下评论,我可以扩展我的答案。

(*)等待轮询的理论原因如下:

假设我有这样的代码:

//START
Begin();
while (!Done())
    Thread.Sleep(D);
//STOP

返回true表示操作已经完成。假设这将发生在大约T时间之后。然后:

  • 线程唤醒并检查条件(调用Done()T/D
  • STARTSTOP的持续时间包括预期的D/2,纯粹是因为Thread。睡眠

你应该选择D的值是多少?随着D的增加,从STARTSTOP的预期持续时间呈线性增加。随着D的减少,迭代次数(限制在)随着1/D的增加而增加。这两种方法都不好,找到正确的D是有问题的。

现在将其与事件驱动的等待进行比较:

//START
Begin();
WaitDone();
//STOP

从理论上讲,只要WaitDone()以某种方式神奇地等待,直到操作完成,但不再继续,在等待轮询案例中发现的两个问题都消失了:这个线程等待的时间正好合适——不多也不少!

重申我开始的观点:在。NET、WaitHandle类和派生类型促进了这种方法。

 类似资料:
  • 我是测试自动化的新手,尤其是Selenium。我正在使用Selenium网络驱动程序Eclipse。我遇到的最大问题之一是我们的脚本由于互联网速度或服务器性能而崩溃。我目前使用来解决这个问题。然而,这并不是秘密,强制等待时间直到计时器完成。我试图为下面的脚本找到一个优化的解决方案。在浏览了Stackoverflow上的帖子后,我找到了下面的)循环中提供的解决方案。有人建议使用: 以确保操作(单击按

  • 是否有关于何时使用任务的好规则。延迟对线程。睡觉 具体来说,是否存在一个最低值,以确保其中一个有效/高效 最后,自任务。延迟会导致异步/等待状态机上的上下文切换,使用它会有开销吗

  • 这里的要点是了解实现等待循环的更有效的解决方案,该循环在每次迭代时轮询条件。通过高效,我的意思是“有效的CPU调度”。 我知道代码中使用的等待条件不是“wakeOne”/“wakeAll”指令中使用的“真正的等待条件”,但我想知道对CPU来说,使用假等待条件是否比睡眠更有效。 这里有2个代码片段,它们做同样的事情:等待某些事情发生。这段代码用于工作线程池。因此,当一个线程等待时,其他线程(或其他一

  • 我正在编写一个基于await/sleep范式的网络绑定应用程序。 我更喜欢这样一个答案,不创建任何额外的线程

  • 我想实现这样的事情:用户按下登录按钮,然后标签显示:连接。 0.5秒时间间隔 连接... 0.5秒时间间隔 连接... 等 只是一种视觉效果,表明“引擎盖下”确实发生了什么。 我所得到的并不是我所期望的。我点击按钮,等待1.5秒,然后我得到了“连接…”,缺少前面的两个步骤。 首先,我的类 还有我的class

  • 问题 你想使用生成器(协程)替代系统线程来实现并发。这个有时又被称为用户级线程或绿色线程。 解决方案 要使用生成器实现自己的并发,你首先要对生成器函数和 yield 语句有深刻理解。 yield 语句会让一个生成器挂起它的执行,这样就可以编写一个调度器, 将生成器当做某种“任务”并使用任务协作切换来替换它们的执行。 要演示这种思想,考虑下面两个使用简单的 yield 语句的生成器函数: # Two