python学习笔记22

python学习笔记22

multiprocessing模块

from multiprocessing import Process
import os
# getpid()获取进程id
# getppid()获取父进程id
def func():
	print(os.getpid(),os.getppid())
    
if __name__ == '__main__':
    print('main:',os.getpid(),os.getppid())
    p = Process(target=func)
    p.start() # 开启一个子进程
## main: 3804 17852
## 4152 3804
# 首先main后面打印的是主进程(即这个程序)的进程id和父进程id
# 后面打印出来的是主进程内开启的子进程的进程id和父进程id

Process类

关于上面的代码,有几个问题:

  1. 为什么要使用if __name__ == '__main__'?

    进程之间的所有内存是隔离的。

    在Windows操作系统中,开启子进程后总是import父进程所在的文件。如上程序中,p.start()开启一个子进程后,子进程先导入父进程所在的文件,就将os模块、multiprocessing模块中的Process类和func函数全导入进子进程所在的内存空间。之后再执行func函数就是执行的父进程导入的func函数。所以if __name__ == '__main__'后的所有代码只会在主进程中执行而不会在子进程中执行(即避免了陷入不断创建子进程的死循环)。

  2. 能不能给子进程传递参数?

    是可以的。在Process实例化的时候可以在参数里设置,如p = Process(target=func,args=(a,b,c,d))这里的参数设置必须是一个元组。

  3. 能否获取子进程的返回值?

    这里是不能获取的。当子进程真正开启时,父进程和子进程的内存就隔离了。

  4. 能否同时开启多个子进程?

    这个是可以的。

    if __name__ == '__main__':
        print('main:',os.getpid(),os.getppid())
        p = Process(target=func)
        p.start() # 开启一个子进程
        p1 = Process(target=func)
        p1.start() # 开启第二个子进程
        p2 = Process(target=func)
        p2.start() # 开启第三个子进程
        #...
        # 这里开启多个子进程的操作是并发异步执行的
        # p.start()是一个典型的异步非阻塞的程序代码
    

join的用法

from multiprocessing import Process
import os
# getpid()获取进程id
# getppid()获取父进程id
def func():
	print('正在执行')
    
if __name__ == '__main__':
    print('开始执行')
    p = Process(target=func)
    p.start() # 开启一个子进程
    print('执行完毕')
# 如果直接运行,结果为:
"""
开始执行
执行完毕
正在执行
"""
# 这是因为程序在开启子进程后并未停顿,直接运行后续代码
# 只需在开启子进程后加入代码p.join()
# 就可以让程序停顿直到子进程执行完毕
if __name__ == '__main__':
    print('开始执行')
    p = Process(target=func)
    p.start() # 开启一个子进程
    p.join() # 阻塞:直到子进程执行完毕才继续执行后续代码
    print('执行完毕')
"""
开始执行
正在执行
执行完毕
"""
#### 当有多个子进程时,需要等所有子进程全部开启之后再对每个子进程进行join()

同步阻塞、异步非阻塞

同步阻塞的例子:上面使用的join函数

异步非阻塞的例子:上面使用的start函数

使用多进程实现一个并发的socket的server端

# Server端
import socket
from multiprocessing import Process

def talk(conn):
    while True:
        msg = conn.recv(1024).decode('utf-8')
        ret = msg.upper().encode('utf-8')
        conn.send(ret)
    conn.close()

if __name__ == '__main__':
    sk = socket.socket()
    sk.bind(('127.0.0.1',9004))
    sk.listen()
    while True:
	    conn,addr = sk.accept() # 接收一个连接就开启一个子进程
        Process(target=talk,args=(conn,)).start()

sk.close()
# Client端
import socket

sk = socket.socket()
sk.connect(('127.0.0.1',9004))

while True:
    sk.send(b'hello')
    msg = sk.recv(1024).decode('utf-8')
    print(msg)
    
sk.close()

这时候的Server端就是通过一个简单的子进程实现了接收并发客户端消息的功能。

posted @ 2020-04-09 21:16  卡奇欧  阅读(94)  评论(0)    收藏  举报