监听程序都是 while(true){......}或者死循环吗?

今天搭建 laravel 的队列,执行了 php artisan queue:work 命令,和同事讨论是不是是一个死循环。进而上升到 tcp 监听 ip: 端口号,apache 其实都是死循环程序(while (true){…..}), 他认为不是,觉得死循环太 low, 而且程序怎么能写死循环呢,这样太消耗系统资源。
我的关观点是:不论什么语言,所有的程序无非 顺序执行 分支执行(if else) 循环执行。既然是监听程序,那就是永不退出的程序,那就只能是死循环,没有别的选择

他的观点是:(他之前是写 java 的)具体是什么也不清楚,但是绝对不是死循环这么 low,尤其是 tcp 链接监听数据,可能是 timer。

我事后又在想,其实很多程序都是不退出的,比如正在运行的 win 操作系统,打开的窗口,其实都是不退出,但是不退出除了死循环还有比的方式吗?我倒是 不是想争论对错,就是突然对这个问题来了兴趣,想来求证一下,有哪位大神可以解说一下吗?非常感谢

Complicated
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
最佳答案

具体得看你的循环逻辑里面有没有导致进程阻塞的操作。如果不会阻塞的话,那的确会占用系统资源。不过一般死循环里面都是放一些通讯相关的逻辑,比如 tcp 监听,这些是会导致进程进入阻塞态的。在阻塞态的进程是不占用什么系统资源的,只是在 cpu 进程调度的时候多循环一次而已。

比如下面这段代码:

socket_accept 这里会阻塞,在没有新的连接到来的时候,进程是阻塞的,cpu 在进程调度的时候,看到这个进程是阻塞的,就去看下一个进程的状态了。


do {
    if (($msgsock = socket_accept($socket)) === false) {
        echo "Error: socket_accept: " . socket_strerror(socket_last_error($socket)) . "\n";
        break;
    }

   // 省略具体逻辑...

} while (true);

具体可以看看操作系统原理进程调度相关的内容。

4年前 评论
讨论数量: 30

以前我也有同样的疑问,现在我感觉就是死循环

4年前 评论

具体得看你的循环逻辑里面有没有导致进程阻塞的操作。如果不会阻塞的话,那的确会占用系统资源。不过一般死循环里面都是放一些通讯相关的逻辑,比如 tcp 监听,这些是会导致进程进入阻塞态的。在阻塞态的进程是不占用什么系统资源的,只是在 cpu 进程调度的时候多循环一次而已。

比如下面这段代码:

socket_accept 这里会阻塞,在没有新的连接到来的时候,进程是阻塞的,cpu 在进程调度的时候,看到这个进程是阻塞的,就去看下一个进程的状态了。


do {
    if (($msgsock = socket_accept($socket)) === false) {
        echo "Error: socket_accept: " . socket_strerror(socket_last_error($socket)) . "\n";
        break;
    }

   // 省略具体逻辑...

} while (true);

具体可以看看操作系统原理进程调度相关的内容。

4年前 评论

楼上说的差不多了,tcp 监听,本质就是读写 socket, 没有信息传输的情况下,进程处于阻塞态,不信你可以在相关循环的代码调试输出某个字符串看看,只有当有数据来的时候,才会输出你调试的字符串,所以看似是死循环,实质上大部分时间,都没有在执行

4年前 评论
李铭昕

就是死循环,但不是这种死循环

while(true){
    echo 1;
}
4年前 评论
JaguarJack

死循环要和阻塞联系在一起。如果你的程序 while (true)没有阻塞的话,那么就是极大消耗 CPU,因为没有让出调度。一直处于工作状态。

4年前 评论

php cli 模式 是无法常驻内存的,要是现实守护进程的方式去运行 while (true) 是一一种最简单的方式

4年前 评论
MysicGi 2年前

blog.csdn.net/songchuwang1868/arti... 建议你看看这篇文章,Apache 这样的服务器都是调用了 linux 提供的 epoll () 或者 select () 相关函数,这些函数在没有网络数据到达的时候是吊起来的,不消耗 CPU 资源,你说的在 php 或者 java 里 while (true) 这样的语法就不停消耗 CPU 了,你说的 apache 和 php 的死循环就是两回事了,所以看底层的一些 C 语言函数和讲解对于理解网络结构我感觉是挺有帮助的

4年前 评论
xianyunyehe

基本上是阻塞进程。你的 while 如果要适当 sleep,阻塞一下,不然不会让出 CPU

4年前 评论
Complicated

@youkr socket_accept()阻塞状态不是一个死循环吗?要不怎么让进程一直阻塞在哪里呢?

4年前 评论
youkr 4年前
Complicated

@chen05_20 那阻塞本身不得是死循环吗?要不怎么阻塞呢?

4年前 评论
poker_face 4年前
Complicated

@李铭昕 哪是哪种死循环?还有别的写法吗?有什么资料可以看一下吗?

4年前 评论
Complicated

@arvin-hermit 但就 php 而言,不借助 swoole 这样的东西,我感觉只能 while (true){。。。。} 了

4年前 评论
Complicated

@youkr 您的意思是说 tcp 是死循环,但是这个死循环是 “阻塞状态” 的那种死循环?

4年前 评论
youkr 4年前

很久之前的代码 php5.3 我们队列都是很简单的,redis 弹出数据消费 没有时 sleep 几秒 while (true){ echo 111; //todo }

4年前 评论

可以说是死循环,只是大部分时间是阻塞状态,此时进程是不消耗 cpu 资源的,只是占用一些内存。所有不存在消耗多少资源的。常规的死循环就不行了,这时 cpu 还是(大概)分配在该进程上。(分时操作系统,cpu 调度)

4年前 评论
godruoyi

举几个列子吧。

Laravel 中的队列监听核心代码如下 github.com/illuminate/queue/blob/m... file

Go 语言中 net/http 提供 http 服务的源码 github.com/golang/go/blob/master/s...

file

4年前 评论
godruoyi (作者) 4年前
kphcdr 4年前
月亮不回家 4年前
ShiKi

@godruoyi 老哥这是什么字体,感觉有点帅

4年前 评论

死循环是没错,但是你 while (true){} 中没有阻塞函数的,你会发现 CPU 疯转,当有阻塞方法时则不会。

4年前 评论

while (true) 简单,我这写 C# 也用的 while (true) :joy:

4年前 评论

不一定都是死循环, 打个比方, 就按照你的这种 title 来说, 消费队列 用 while(1){ } 确实也是一种方法,1. 同步消费, 只是这种方法是同步在消费,一直在监控这队列,2. 异步消费, 还有一种办法 叫异步回调,就是队列里面有数据透底近来了, 然后通过回调函数去处理,也能达到实时去消费队列的场景,

4年前 评论

看了上面的回答,我个人觉得就是死循环。只不过是内部处理不同罢了。比如网络通讯,在没有外部网络到来的时候,调用系统函数,让程序自身暂停,等待请求到来,让出系统资源,然后执行后面的代码处理这个请求,然后继续等待。
协程感觉很好诠释了这个问题。

4年前 评论
Complicated

@欧皇降临 其实我感觉也是死循环,只不过 循环内部调用了函数,让进程处于某种 “省资源” 的状态

4年前 评论