三. 并发编程 (程序中的进程操作)

一 .程序中的进程操作

1. multiprocess模块

仔细说来,multiprocess不是一个模块而是python中一个操作、管理进程的包。 之所以叫multi是取自multiple的多功能的意思,在这个包中几乎包含了和进程有关
的所有子模块。由于提供的子模块非常多,为了方便大家归类记忆,我将这部分大致分为四个部分:创建进程部分,进程同步部分,进程池部分,进程之间数据共享。

process模块介绍

process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建。

 2. 进程(参数 方法 属性 注意事项)

参数说明
Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)
强调:
1. 需要使用关键字的方式来指定参数
2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号

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


方法介绍
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开启的进程 属性介绍 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字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时
才能成功(了解即可)
在windows中使用process模块的注意事项 在Windows操作系统中由于没有fork(linux操作系统中创建进程的机制),在创建子进程的时候会自动
import 启动它的这个文件,而在 import
的时候又执行了整个文件。因此如果将process()直接写在文件中就会无限递归创建子进程报错。所以必须把创建子进程的部分使用if __name__ ==‘__main__
判断保护起来,import 的时候 ,
就不会递归运行了。

 3. 进程创建使用

from  multiprocessing import Process

def run():
    print("22222")
if __name__=="__main__":
    p=Process(target=run)      #  实例化进程
    p.start()


print("*******************************************")

# 进程传参数
def run(*args):
    print(args)
if __name__=="__main__":
    p=Process(target=run,args=(10,20,30))      #  实例化进程
    p.start()

print("*******************************************")

# 来查看进程直间的关系   os.getpid() 查看当前进程号    os.getppid() 查看当前父进程号  
def run(*args):
    print(args)
    time.sleep(1)
    print(1111111111111111111111111111)
    print(os.getpid(),"查看当前子进程号3")       # 1748   # os.getpid() 查看当前进程号
    print(os.getppid(),"查看父进程号4")          # 10120   os.getppid() 查看当前父进程号

if __name__ == "__main__":
    p1 = Process(target=run, args=(10, 20, 30))  # 实例化进程
    p1.start()
    print("我是主进程。。。。。")
    print(os.getpid(),"查看当前主进程号1")          #10120      # os.getpid() 查看当前进程号
    print(os.getppid(),"查看当前执行父进程号2")     #  7372  #   os.getppid() 查看当前父进程号
    print(p1.name)                                 # Process-1

print("*******************************************")

# 多进程
"""multiprocessing 库
是一个跨平台版本多进程模块 提供了一个Process类来代表一个进程对象
"""
from multiprocessing import Process
from time import sleep
import os
# 子进程需要执行代码
def run(str):
    print("子进程启动了")
    sleep(3)
    print("子进程结束")

if __name__ == "__main__":
    print("main是主(父)进程启动....")
    # 01 创建进程 子进程
    p=Process(target=run,args =("nice",))  #    target 说明进程执行的指定代码(函数)
    # 02  启动进程
    # 父进程的结束不能影响子进程 让父进程等待子进程结束在执行父进程
    p.start()
    print("父进程结束....")
    sleep(2)

# 执行顺序
#     main是主(父)进程启动....
#     父进程结束....
#     子进程启动了
#     子进程结束



4. 多进程启动(for循环 join进程感知)

def run(*args):
       print(args)
if __name__=="__main__":
    p1=Process(target=run,args=(10,20,30))      #  实例化进程
    p1.start()
    p2= Process(target=run, args=(555,666,777))
    p2.start()
    print("我是主进程")

print("***********************************************"def run(*args):
    print(args)
if __name__ == "__main__":
    for i in  range(5):
        p1 = Process(target=run, args=(10, 20, 30))  # 实例化进程
        p1.start()

print("***********************************************"
进程方法应用join 感知进程结束 相当于异步程序 改为同步程序 def run(*args): print(args) print("我是子进程2222222222222") time.sleep(2) print("我是子进程333333333333") if __name__ == "__main__": p1 = Process(target=run, args=(10, 20, 30)) # 实例化进程 p1.start() p1.join() # 应用join 感知进程结束 相当于异步程序 改为同步程序 有一个阻塞效果 就是子进程结束完了才执行主进程 print("我是主进程111111111111")
print("***********************************************"
join 进程方法应用感知 def run(): print("我是子进程2222222222222") time.sleep(2) # 在这休息两秒 但是程序没有停下 在休息2秒的过程中 他在执行上面打印4次 就没有等 在执行下面打印4次 print("我是子进程333333333333") if __name__ == "__main__": ret=[] for i in range(4): p1 = Process(target=run,) # 实例化进程 ret.append(p1) p1.start() for p in ret: p.join() #等待 上面所以进程必须执行完了才能执行下面代码 在join之前是异步执行 当遇到join有个阻塞效果就变成同步执行 print("完成了哈哈哈.......") # 就相当于在join之前 开辟了四条跑道 这四个进程在各自的跑道跑 但是这四个进程有跑的慢的和跑的快的(意思就是每个进程速度不一样) # 当遇到join 跑的快的进程要等跑的慢的进程(意思就是四个进程都跑完) 在计算成绩各自跑的成绩 就变成了同步
print("***********************************************"
join(进程方法应用join 感知进程结束 相当于异步程序 改为同步程序)
def run(filename,coon): with open(filename,"w") as f1: f1.write(coon*10*'*') if __name__ == "__main__": ret=[] for i in range(4): p1 = Process(target=run,args=("info%s"%i,i)) # 实例化进程 ret.append(p1) p1.start() print(ret) for p in ret:p.join() # 等待上面写完了在向用户展示所以写的文件 # 有个阻塞等待效果 join之前是异步写入 遇到join变同步写入完了 才能执行下面代码 print([i for i in os.walk(r"H:python之路2day1")]) # # 同步0.1=400 =40 # 异步 400 0.1 =0.1
print("***********************************************"
通个类继承来实现开启多个进程
class MyProcess(Process): def __init__(self,a,b): super().__init__() # 继承Proceess self.a=a self.b=b def run(self): print(self.a) print(self.b) print(self.pid) if __name__=="__main__": p1=MyProcess(1,2) p1.start() #相当于 # p2.run() 只是内部作为处理的 p2 = MyProcess(555, 99999) p2.start() # 相当于 # p2.run() 只是内部作为处理的 p1.join() p2.join() print("我是主进程!!!!!!!!!!!!!!1")




print("**********************************************************")


进程池概念 Pool
import os,time,random
from multiprocessing import Pool   # 多进程就用Pool  (进程池)


def run(name):

    print("子进程启动22222",name,getpid())
    print("子进程程结束2222",name,getpid())

if __name__ == '__main__':

    print("父进程启动11111")

    # 01 创建多个进程
    #     进程池
    #      表示可以同时执行进程数量
    #      Pool默认大小是cpu核心数
    pp=Pool(2)
    for i in range(5):
        # 02 创建进程 放入进程池统一管理
        pp.apply_async(run,args=(i,))
        
#apply 阻塞       同步方法
# apply_async  阻塞     异步方法

# 注意:在调用join之前必须先调用close 调用close之后就不能再继续添加新的进程了
pp.close()
#注意: 是进程池对象调用join会等待进程池中所有的子进程结束完毕再去执行父进程
pp.join()
print("父进程结束11111")
# 多进程
"""multiprocessing 库

是一个跨平台版本多进程模块 提供了一个Process类来代表一个进程对象
"""
from multiprocessing import Pool   #  使用多进程
import os ,time ,random

def run(name):
     print("子进程启动--%s"%(name,os.getpid()))
     # print(name,os.getpid())
     start=time.time()
     time.sleep(random.choiec([1,2,3]))
     end=time.time()
     print("子进程%d结束--%s--耗时%2.f"%(name,os.getpid(),end-start))
     # print(name,os.getpid(),end-start)
     # 
if __name__=="__main__":

  print("父进程启动......................")

   # 01创建多进程
   #    进程池
   # Pool()  默认是大小cpu核心数   
  pp=Pool(2)     #表示可以同时执行的进程数量

  for i in range(3):  # 创建3个进程
        # 创建进程,放入进程池统一管理
        pp.apply_async(run,args=(i,))

   # 在调用join之前必须先调用close调用close之后就不能再继续添加新的进程了
  pp.close()
   # 进程池对象调用join 会等待进程池中所有的子进程结束完毕再去执行父进程
  pp.join()
  print("父进程结束......................")

 5. 进程之间数据隔离

n=20
def run():
    global n
    n = 60
    print(n)  # 60
run()
print(n)   # 60


print("*********************************************")

num=100
# 说明子进程和父进程用的num是完全不同的   是两个完全不同的变量
def run():
     print("子进程开始")
     global num            #global 表示使用全局变量
     num+=1
     print(num)
     print("子进程结束")

if __name__=="__main__":
     print("父进程开始")
     p=Process(target=run)
     p.start()
     p.join()
     print("父进程结束---",num)
# 在子进程中修改全局变量对父进程中的全局变量没有影响
# 在创建子进程时对全局变量做了个备份  
# 在父进程和子进程中的num是两个完全不同的变量
# 执行顺序
#     父进程开始
#     子进程开始
#     101
#     子进程结束
#     父进程结束--- 100


print("*********************************************")

def run():
    global n
    n=1000
    print("子进程",os.getpid(), n) # 子进程 8016 1000

if __name__ == "__main__":
    n = 600
    p1 = Process(target=run)  # 实例化进程
    p1.start()
    p1.join()       # 阻塞等待子进程结束后才执行主进程
    print("主进程",os.getpid(),n)    # 主进程 5244 600


print("*********************************************")

    def work():
    global n
    n=222
    print('子进程内: ',n)  # 子进程内:  222
if __name__ == '__main__':
    n = 100
    p=Process(target=work)
    p.start()
    print('主进程内: ',n)  # 主进程内:  100

 6. 进程实现网络编程(注意子进程中不能加input)

server
from socket import *
from multiprocessing import Process
server=socket(AF_INET,SOCK_STREAM)
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
server.bind(('127.0.0.1',8080))
server.listen(5)

def run(conn,addr):
    print(addr)
    while True:
        msg=conn.recv(1024)
        conn.send(msg.upper())

if __name__ == '__main__':
    while True:
        conn,addr=server.accept()
        p=Process(target=run,args=(conn,addr))
        p.start()

print"*******************************************"client
from socket import *
client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))

while True:
    msg=input('请输入字母: ').strip()
    client.send(msg.encode('utf-8'))
    msg=client.recv(1024)
    print(msg.decode('utf-8'))

 7. 守护进程

会随着主进程的结束而结束。

主进程创建守护进程
  其一:守护进程会在主进程代码执行结束后就终止
  其二:守护进程内无法再开启子进程,否则抛出异常
注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止。
import os
import time
from multiprocessing import Process
"""class Myprocess(Process):
    def __init__(self,person):
        super().__init__()
        self.person = person
    def run(self):
        print(os.getpid(),self.name)
        print('%s正在吃饭' %self.person)

if __name__=="__main__":
    p = Myprocess('张三')
    p.daemon = True  # 一定要在p.start()前设置,设置p为守护进程,禁止p创建子进程,并且父进程代码执行结束,p即终止运行
    p.start()
    time.sleep(2)  # 在sleep时查看进程id对应的进程ps -ef|grep id
    print('主进程')


print("******************************************************")



def run1():
    while True:
        time.sleep( 0.2)
        print("我还活起的!!!!!!!!")

if __name__=="__main__":
    p1=Process(target=run1)
    p1.daemon = True      #  设置守护进程   (主进程代码执行结束 子进程代码也会自然而然结束   )
    p1.start()            # 随着主进程代码结束完毕 的结束  而结束
    print(p1.is_alive())   #  判断进程是否或着
    i=0
    while i<5:
        print("我是主进程1111111111111111111")
        time.sleep(2)
        i+=1
    print(p1.is_alive())    #  判断进程是否或着


print("******************************************************")

def foo():
    print(123)
    time.sleep(1)
    print("end123")

def bar():
    print(456)
    time.sleep(3)
    print("end456")

p1=Process(target=foo)
p2=Process(target=bar)
if __name__=="__main__":
    p1.daemon=True
    p1.start()
    p2.start()
    time.sleep(0.1)
    print("main-------")
    # 打印该行则主进程代码结束,则守护进程p1应该被终止.#可能会有p1任务
    # 执行的打印信息123,因为主进程打印main----时,p1也执行了,但是随即被终止.
    # main - ------
    # 456
    # end45

 8. 进程方法is_alive()  and    terminate()

from multiprocessing import Process
import time
import random

class Myprocess(Process):
    def __init__(self,person):
        self.name=person
        super().__init__()

    def run(self):
        print('%s正在和网红脸聊天' %self.name)
        time.sleep(2)
        print('%s还在和网红脸聊天' %self.name)

if __name__ == '__main__':

    p1=Myprocess('顺悟空')
    p1.start()

    p1.terminate()#  结束一个子进程      关闭进程,不会立即关闭,所以is_alive立刻查看的结果可能还是存活
    print(p1.is_alive()) #结果为True     检查进程状态 是否活着

    print('开始')
    print(p1.is_alive()) #结果为False

    print("我是主进程哈哈哈哈哈")

# p1.terminate()   在主进程中结束一个子进程 结束一个子进程不是执行了立马生效 需要一个操作系统响应的过程
原文地址:https://www.cnblogs.com/Sup-to/p/11180748.html