【tulip】 - 多进程的版本

来源:互联网 发布:淘宝店铺被扣了48分 编辑:程序博客网 时间:2024/05/19 02:02

前面的网络编程的例子使用多进程也是可以实现的:

import socketimport osdef main():    listen_sock = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=socket.IPPROTO_IP)    listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)    listen_sock.bind(('0.0.0.0', 9090))    listen_sock.listen(0)    while True:        conn_sock, client_addr = listen_sock.accept()        pid = os.fork()        if pid == 0: # I am child process            serve(conn_sock, client_addr)        else: # I am parent process            conn_sock.close()def serve(conn_sock, client_addr):    print('connected from %s:%s' % client_addr)    input = conn_sock.recv(8192)    while 'done' != input.strip():        conn_sock.sendall(input)        input = conn_sock.recv(8192)    conn_sock.sendall('bye!\n')    conn_sock.close()main()

其中os.fork()之后会创建一个子进程。子进程默认会继承所有父进程的所有file descriptor(也就包括打开的socket),已经拥有fork前父进程的所有内存状态。所以子进程可以拿着父进程打开的conn_sock继续与客户端通信。而父进程在把conn_sock交给子进程之后,就不再需要开着这个socket的fd了,所以就需要关闭掉。否则,子进程调用conn_sock.close()之后,客户端的连接其实还没有断开,因为父进程还拿着fd不放呢。
从调度的角度来看,前面说的两个要素:

  • 状态的保存:仍然是保存在栈上。每个进程都有一个主线程。fork出来的子进程的主线程的栈上保存了对应客户端的conn_sock。
  • 不同socket之间的调度:仍然是利用内核的scheduler,只是这次调度的是process。对于内核来说调度逻辑是差不多的,区别就是process还要额外更新一下虚拟内存的映射表,使得多个process彼此之间不可见对方的内存。

从效率上来说,具有多线程一样的问题,而且内存占用会更高,切换成本也更高。多线程和多进程的版本从代码可读性上来说还是非常不错的,很好懂,从上至下平铺直叙的。

0 0