multiprocess模块

主要内容

  • 1.process  模块介绍
  • 2.process类的使用
  • 3.守护进程

1.process  模块介绍

(1)process类中的参数

参数介绍:
1 group参数未使用,值始终为None
2 target表示调用对象,即子进程要执行的任务
3 args表示调用对象的位置参数元组,args=(1,2,'egon',)
4 kwargs表示调用对象的字典,kwargs={'name':'egon','age':18}
5 name为子进程的名称
process类中的参数

当给执行参数传参

from multiprocessing import Process
def func1(n):
    print('>>>',n)

if __name__ == '__main__':
    #两种传参方式:
    # p1 = Process(target=func1,args=(1,))
    p1 = Process(target=func1,kwargs={'n':1})
    p1.start()
    print('主进程结束')
两种传参方式

(2)Process类中各方法的介绍

p.start():启动进程,并调用该子进程中的p.run() 
p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法  
p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
p.is_alive():如果p仍然运行,返回True
p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
Python类中的方法介绍

join方法

让主进程加上join的地方等待(也就是阻塞住),等待子进程执行完之后,再继续往下执行我的主进程,好多时候,我们主进程需要子进程的执行结果,所以必须要等待。join感觉就像是将子进程和主进程拼接起来一样,将异步改为同步执行。

import time
from multiprocessing import Process

def fun1(n):
    time.sleep(n)
    print('func1',n)
def fun2(n):
    time.sleep(n)
    print('fun2',n)
def fun3(n):
    time.sleep(n)
    print('func3',n)

if __name__ == '__main__':

    p1 = Process(target=fun1,args=(1,))
    p2 = Process(target=fun2,args=(2,))
    p3 = Process(target=fun3,args=(3,))

    p1.start()
    p2.start()
    p3.start()
验证下并发的并发时间
import time
from multiprocessing import Process
# 验证join方法
global_num = 100
def func1():
    time.sleep(2)
    global global_num
    global_num = 0
    print('子进程全局变量>>>',global_num)

if __name__ == '__main__':
    p1 = Process(target=func1,)
    p1.start()
    print('子进程执行')
    p1.join()  #阻塞住,等待你的p1子进程执行结束,主进程的程序才能从这里继续往下执行
    print('主进程的全局变量>>>',global_num)
验证join 1
# for循环在创建进程中的应用
import time
from multiprocessing import Process

def fun1(n):
    time.sleep(1)
    print(n)

if __name__ == '__main__':
    pro_list = []
    for i in range(10):
        p1 = Process(target=fun1,args=(i,))
        p1.start()
        pro_list.append(p1)
        # p1.join()

    for p in pro_list:
        p.join()

    print('主进程结束')
for循环在创建进程中的应用
#下面的注释按照编号去看,别忘啦!
import time
import os
from multiprocessing import Process

def func(x,y):
    print(x)
    # time.sleep(1) #进程切换:如果没有这个时间间隔,那么你会发现func执行结果是打印一个x然后一个y,再打印一个x一个y,不会出现打印多个x然后打印y的情况,因为两个打印距离太近了而且执行的也非常快,但是如果你这段程序运行慢的话,你就会发现进程之间的切换了。
    print(y)

if __name__ == '__main__':

    p_list= []
    for i in range(10):
        p = Process(target=func,args=('姑娘%s'%i,'来玩啊!'))
        p_list.append(p)
        p.start()

    [ap.join() for ap in p_list] #4、这是解决办法,前提是我们的子进程全部都已经去执行了,那么我在一次给所有正在执行的子进程加上join,那么主进程就需要等着所有子进程执行结束才会继续执行自己的程序了,并且保障了所有子进程是异步执行的。

        # p.join() #1、如果加到for循环里面,那么所有子进程包括父进程就全部变为同步了,因为for循环也是主进程的,循环第一次的时候,一个进程去执行了,然后这个进程就join住了,那么for循环就不会继续执行了,等着第一个子进程执行结束才会继续执行for循环去创建第二个子进程。
        #2、如果我不想这样的,也就是我想所有的子进程是异步的,然后所有的子进程执行完了再执行主进程
    #p.join() #3、如果这样写的话,多次运行之后,你会发现会出现主进程的程序比一些子进程先执行完,因为我们p.join()是对最后一个子进程进行了join,也就是说如果这最后一个子进程先于其他子进程执行完,那么主进程就会去执行,而此时如果还有一些子进程没有执行完,而主进程执行
         #完了,那么就会先打印主进程的内容了,这个cpu调度进程的机制有关系,因为我们的电脑可能只有4个cpu,我的子进程加上住进程有11个,虽然我for循环是按顺序起进程的,但是操作系统一定会按照顺序给你执行你的进程吗,答案是不会的,操作系统会按照自己的算法来分配进
              #程给cpu去执行,这里也解释了我们打印出来的子进程中的内容也是没有固定顺序的原因,因为打印结果也需要调用cpu,可以理解成进程在争抢cpu,如果同学你想问这是什么算法,这就要去研究操作系统啦。那我们的想所有子进程异步执行,然后再执行主进程的这个需求怎么解决啊
    print('不要钱~~~~~~~~~~~~~~~~!')

代码
for循环的详细解释

process类中自带的封装的各属性的介绍

p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
p.name:进程的名称
p.pid:进程的pid
p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)
类中各属性介绍

练习:模拟两个应用场景:1、同时对一个文件进行写操作  2、同时创建多个文件

2.process类的使用

 

注意:在windows中Process()必须放到# if __name__ == '__main__':下

Since Windows has no fork, the multiprocessing module starts a new Python process and imports the calling module. 
If Process() gets called upon import, then this sets off an infinite succession of new processes (or until your machine runs out of resources). 
This is the reason for hiding calls to Process() inside

if __name__ == "__main__"
since statements inside this if-statement will not get called upon import.
由于Windows没有fork,多处理模块启动一个新的Python进程并导入调用模块。 
如果在导入时调用Process(),那么这将启动无限继承的新进程(或直到机器耗尽资源)。 
这是隐藏对Process()内部调用的原,使用if __name__ == “__main __”,这个if语句中的语句将不会在导入时被调用。

原因解释
相关解释

(1)进程创建的第二种方法

class MyProcess(Process): #自己写一个类,继承Process类
    #我们通过init方法可以传参数,如果只写一个run方法,那么没法传参数,因为创建对象的是传参就是在init方法里面,面向对象的时候,我们是不是学过
    def __init__(self,person):
        super().__init__()
        self.person=person
    def run(self):
        print(os.getpid())
        print(self.pid)
        print(self.pid)
        print('%s 正在和女主播聊天' %self.person)
    # def start(self):
    #     #如果你非要写一个start方法,可以这样写,并且在run方法前后,可以写一些其他的逻辑
    #     self.run()
if __name__ == '__main__':
    p1=MyProcess('Jedan')
    p2=MyProcess('太白')
    p3=MyProcess('alexDSB')

    p1.start() #start内部会自动调用run方法
    p2.start()
    # p2.run()
    p3.start()


    p1.join()
    p2.join()
    p3.join()

继承的形式创建进程
方法解释
from multiprocessing import Process
import os
class MyProcess(Process):
    def __init__(self,n,name):
        super().__init__() #此处当执行到run方法,当自己要定义参数时首先要用super()来调用父类中的__init__方法,由此可以进行传参
        self.n = n
        self.name = name

    def run(self):
        print(11111)
        print("子进程的进程ID",os.getpid())
        print("你看看>>",self.n)

if __name__ == "__main__":
    p1 = MyProcess(100,name="子进程")
    p1.start()
    print("p1.name",p1.name)
    print("p1.pid ",p1.pid)
    print("主进程结束")
一个例子

(2)进程之间是隔离的

#我们说进程之间的数据是隔离的,也就是数据不共享,看下面的验证
from multiprocessing import Process
n=100 #首先我定义了一个全局变量,在windows系统中应该把全局变量定义在if __name__ == '__main__'之上就可以了
def work():
    global n
    n=0
    print('子进程内: ',n)

if __name__ == '__main__':
    p=Process(target=work)
    p.start()
    p.join() #等待子进程执行完毕,如果数据共享的话,我子进程是不是通过global将n改为0了,但是你看打印结果,主进程在子进程执行结束之后,仍然是n=100,子进程n=0,说明子进程对n的修改没有在主进程中生效,说明什么?说明他们之间的数据是隔离的,互相不影响的
    print('主进程内: ',n)

#看结果:
# 子进程内:  0
# 主进程内:  100

进程的内存空间是隔离的
进程之间是隔离的
import time
from multiprocessing import Process
global_num = 100
def func1():
    global global_num
    global_num = 0
    print('子进程全局变量>>>',global_num)

if __name__ == '__main__':
    p1 = Process(target=func1,)
    p1.start()
    time.sleep(1)
    print('主进程的全局变量>>>',global_num)
隔离的例子

练习   那我们自己通过多进程来实现一下同时和多个客户端进行连接通信(这里不考虑socketserver那个模块)

  服务端代码示例:(注意一点:通过这个是不能做qq聊天的,因为qq聊天是qq的客户端把信息发给另外一个qq的客户端,中间有一个服务端帮你转发消息,而不是我们这样的单纯的客户端和服务端对话,并且子进程开启之后咱们是没法操作的,并且没有为子进程input输入提供控制台,所有你再在子进程中写上了input会报错,EOFError错误,这个错误的意思就是你的input需要输入,但是你输入不了,就会报这个错误。而子进程的输出打印之类的,是pycharm做了优化,将所有子进程中的输出结果帮你打印出来了,但实质还是不同进程的。)
提示
from socket import *
from multiprocessing import Process

def talk(conn,client_addr):
    while True:
        try:
            msg=conn.recv(1024)
            print('客户端消息>>',msg)
            if not msg:break
            conn.send(msg.upper())
            #在这里有同学可能会想,我能不能在这里写input来自己输入内容和客户端进行对话?朋友,是这样的,按说是可以的,但是需要什么呢?需要你像我们用pycharm的是一样下面有一个输入内容的控制台,当我们的子进程去执行的时候,我们是没有地方可以显示能够让你输入内容的控制台的,所以你没办法输入,就会给你报错。
        except Exception:
            break

if __name__ == '__main__': #windows下start进程一定要写到这下面
    server = socket(AF_INET, SOCK_STREAM)
    # server.setsockopt(SOL_SOCKET, SO_REUSEADDR,1)  # 如果你将如果你将bind这些代码写到if __name__ == '__main__'这行代码的上面,那么地址重用必须要有,因为我们知道windows创建的子进程是对整个当前文件的内容进行的copy,前面说了就像import,如果你开启了子进程,那么子进程是会执行bind的,那么你的主进程bind了这个ip和端口,子进程在进行bind的时候就会报错。
    server.bind(('127.0.0.1', 8080))
    #有同学可能还会想,我为什么多个进程就可以连接一个server段的一个ip和端口了呢,我记得当时说tcp的socket的时候,我是不能在你这个ip和端口被连接的情况下再连接你的啊,这里是因为当时我们就是一个进程,一个进程里面是只能一个连接的,多进程是可以多连接的,这和进程之间是单独的内存空间有关系,先这样记住他,好吗?
    server.listen(5)
    while True:
        conn,client_addr=server.accept()
        p=Process(target=talk,args=(conn,client_addr))
        p.start()

tcp_server.py
实现代码
from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))


while True:
    msg=input('>>: ').strip()
    if not msg:continue

    client.send(msg.encode('utf-8'))
    msg=client.recv(1024)
    print(msg.decode('utf-8'))

tcp_client.py
client

 

posted @ 2018-10-23 21:16  一路向北_听风  阅读(337)  评论(0编辑  收藏  举报