监听程序都是 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);

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

3年前 评论
讨论数量: 30

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

3年前 评论

具体得看你的循环逻辑里面有没有导致进程阻塞的操作。如果不会阻塞的话,那的确会占用系统资源。不过一般死循环里面都是放一些通讯相关的逻辑,比如 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);

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

3年前 评论

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

3年前 评论
李铭昕

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

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

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

3年前 评论

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

3年前 评论
MysicGi 1年前

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

3年前 评论
xianyunyehe

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

3年前 评论
Complicated

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

3年前 评论
youkr 3年前
Complicated

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

3年前 评论
poker_face 3年前
Complicated

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

3年前 评论
Complicated

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

3年前 评论
Complicated

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

3年前 评论
youkr 3年前

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

3年前 评论

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

3年前 评论
godruoyi

举几个列子吧。

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

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

file

3年前 评论
godruoyi (作者) 3年前
kphcdr 3年前
gaooooge 3年前
ShiKi

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

3年前 评论

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

3年前 评论

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

3年前 评论

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

3年前 评论

好问题 :+1:

3年前 评论

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

3年前 评论
Complicated

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

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!