管道的fd设置成阻塞和非阻塞区别
时间: 2024-06-20 22:00:50 浏览: 6
在Unix/Linux系统中,管道(pipe)是内核提供的一种半连接通信机制,它允许进程间通过文件描述符(file descriptor, fd)进行数据交换。当管道的fd设置为阻塞或非阻塞模式,会影响到读写操作的行为。
**阻塞模式(Blocking):**
当fd设置为阻塞模式时,如果试图从管道读取数据但管道为空(没有数据),或者向管道写入数据但管道已满,操作系统会将调用该操作的线程挂起,直到有数据可读或空间可用。阻塞模式保证了数据的一致性,适合于处理顺序执行、不需要立即响应的情况。
**非阻塞模式(Non-blocking):**
在非阻塞模式下,同样的操作会立即返回,如果管道没有数据或空间,操作系统不会阻塞,而是直接返回错误,如`EAGAIN`(资源暂时不可用)。这使得进程能够更高效地处理并发,因为线程不会因等待IO而阻塞其他操作,适用于事件驱动或高并发场景,但需要程序自行管理IO状态和错误检查。
设置阻塞和非阻塞的主要差别在于性能、可扩展性和应用程序的复杂性:
1. **性能**:非阻塞模式通常更快,因为它减少了不必要的线程阻塞,提高了系统的吞吐量。
2. **并发能力**:非阻塞模式支持高并发,因为多个线程可以同时尝试进行I/O操作,而阻塞可能导致线程竞争同一资源。
3. **代码复杂性**:非阻塞模式需要更多的错误检查和同步逻辑,否则可能会导致数据丢失或死锁。
相关问题
subprocess.popen阻塞
subprocess.Popen在读取子进程的标准输出时,如果子进程没有输出,使用stdout.read()会导致程序阻塞。 为了避免阻塞,可以采用两种方法。一种是在读取输出之前,将文件描述符设置为非阻塞模式,例如使用fcntl库的fcntl函数进行设置。具体实现可以参考下面的代码示例:
```
import select
import os
import subprocess
import time
import fcntl
args = ['python','./fetch_file2.py',ip,path]
proc = subprocess.Popen(args, stdout=subprocess.PIPE,stderr=subprocess.PIPE,close_fds=True)
def non_block_read(output): # 避免阻塞
fd = output.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
try:
return output.read()
except:
return ""
while proc.poll() is None: #fetch中rsync结束。但是fetch没有结束(怀疑输出过大) 导致这里一直是None
pass
print proc.poll() # 杀死fetch进程 返回-9
print proc.stderr.read() #阻塞#方法1:
#non_block_read(proc.stderr) #防止阻塞#方法2:
select_rfds = [ proc.stdout, proc.stderr]
(rfds, wfds, efds) = select.select(select_rfds, [],[])
if proc.stderr in rfds: #不存在。若select_rfds=[stderr],则阻塞在select上
len = proc.stderr.read(10)
if len == 0:
print "empty"
else:
print "proc.stderr"
if proc.stdout in rfds:
print "proc.stdout"
```
通过设置文件描述符为非阻塞模式,可以避免阻塞问题,并且使用select.select来检查子进程的标准输出是否可读。 这样即可解决subprocess.Popen阻塞的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span>
#### 引用[.reference_title]
- *1* [对Python subprocess.Popen子进程管道阻塞详解](https://download.csdn.net/download/weixin_38661128/12866393)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"]
- *2* [python subprocess.Popen read阻塞问题解决](https://blog.csdn.net/weixin_41582874/article/details/127939185)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"]
- *3* [python subprocess阻塞](https://blog.csdn.net/weixin_30855761/article/details/99389411)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"]
[ .reference_list ]
int pipe_init(char *myfifo){ int fd; int res; //判断是否存在命名管道文件 if(access(myfifo,F_OK) != -1){ printf("%s管道存在.\n",myfifo); remove(myfifo); } res = mkfifo(myfifo,0777); if (res < 0) { printf("create fifo failure\n"); exit(1); }else{ printf(">>>Opening pipe...\n"); } /* 打开命名管道 */ fd = open(myfifo, O_WRONLY|O_NONBLOCK);//写,非阻塞状态 if(fd != NULL){ printf(">>>Writing data to Pipe...\n"); }else{ printf(">>> open XXX"); } return fd; }
在这段代码中,存在以下几个问题:
1. open函数返回的是文件描述符,而不是NULL。因此,判断文件是否成功打开,应该使用文件描述符是否小于0来判断,而不是是否等于NULL。
2. 在使用open函数打开管道时,应该使用O_WRONLY|O_NONBLOCK模式。然而,在本代码中却使用了O_WRONLY|O_NONBLOCK这种形式,这是错误的。正确的模式应该是O_WRONLY|O_NONBLOCK。
3. 如果open函数返回的文件描述符小于0,则应该在出错处理中进行处理,例如输出错误信息并退出程序。
下面是修改后的代码:
```c
int pipe_init(char *myfifo) {
int fd;
int res;
// 判断是否存在命名管道文件
if (access(myfifo, F_OK) != -1) {
printf("%s管道存在.\n", myfifo);
remove(myfifo);
}
res = mkfifo(myfifo, 0777);
if (res < 0) {
printf("create fifo failure\n");
exit(1);
} else {
printf(">>>Opening pipe...\n");
}
// 打开命名管道
fd = open(myfifo, O_WRONLY | O_NONBLOCK);
if (fd < 0) {
printf(">>>Failed to open pipe\n");
exit(1);
} else {
printf(">>>Writing data to Pipe...\n");
}
return fd;
}
```
希望能帮到您。