python进程(2)

python进程

multiprocess模块

'process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建'
Process([group [, target [, name [, args [, kwargs]]]]])
#参数介绍:

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

#强调:
1. 需要使用关键字的方式来指定参数
2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号

multiprocess模块方法

#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开启的进程 

join方法

# 代码示例:
import time
from multiprocessing import Process

def func():
    print("子进程开始执行!")
    time.sleep(1)
    print("子进程执行完毕!")

if __name__ == '__main__':
    print("主进程开始执行!")
    p = Process(target=func, )
    p.start()
    p.join()
    print("主进程执行完毕!")

# 执行结果:   
	主进程开始执行!
	子进程开始执行!
	子进程执行完毕!
	主进程执行完毕!

'当主进程执行到p.join()时,整个程序会阻塞在这里,直到子进程p执行完毕,主进程才能继续向下执行,也就不会出现主进程先于子进程执行完毕的现象了'

代码创建进程

第一种创建进程的方式

# 代码示例
from multiprocessing import Process

def dask(name):
    print("%s的子进程"%name)


if __name__ == '__main__':
    p = Process(target=dask, args=('kevin',)) # 创建一个进程对象
    
    p.start() # 告诉操作系统创建一个新的进程
    
    print('主进程')
    """
强调:不同的操作系统创建进程的要求不一样
    在windows中创建进程是以导入模块的方式进行 所以创建进程的代码必须写在__main__子代码中
    否则会直接报错 因为在无限制创建进程
    在linux和mac中创建进程是直接拷贝一份源代码然后执行 不需要写在__main__子代码中
"""

第二种继承的形式创建进程

'自定义一个类,继承Process类,必须写一个run()方法.如果想要传参,可以自己写一个init方法,然后首先执行super父类的init方法,再写自己的属性'
# 代码示例
from multiprocessing import Process

class MyProcess(Process):   # 自定义的类要继承Process类
    def __init__(self, n, name):
        super().__init__()  
 # 如果自己想要传参name, 那么要首先用super()执行父类的init方法
        self.n = n
        self.name = name
    def run(self):
        print("子进程的名字是>>>", self.name)
        print("n的值是>>>", self.n)

if __name__ == '__main__':
    p1 = MyProcess(123, name="子进程01")
    p1.start()  
    # 给操作系统发送创建进程的指令,子进程创建好之后,要被执行,执行的时候就会执行run方法
    print("p1.name是>>>", p1.name)
    print("主进程结束")

# 执行结果:
# p1.name是>>> 子进程01
# 主进程结束
# 子进程的名字是>>> 子进程01
# n的值是>>> 123

进程实现并发

"""
将与客户端通信的代码封装成一个函数 
之后每来一个客户端就创建一个进程专门做交互
"""
# 代码示例:
'将服务端的代码封装成函数'
def get_server():
    server = socket.socket()
    server.bind(('127.0.0.1', 8080))
    server.listen(5)
    return server
'''封装一个get_server,这个创建进程就不会反复执行里面的代码
从而避免报地址只允许使用一次的错误'''

def talk():
    while True:
        data = socket.recv(1024)
        print(data.decode('utf8'))
        sock.send(data)

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

进程间数据默认隔离

'进程之间是空间隔离的,不共享资源'
#代码示例:
import time
from multiprocessing import Process

global_num = 100
def func():    # 子进程
    global global_num
    global_num = 0
    print("子进程的全局变量>>>", global_num)

if __name__ == '__main__':
    p1 = Process(target=func,)
    p1.start()
    time.sleep(1)  # 等待子进程执行结束
    print("主进程的全局变量>>>", global_num)

# 执行结果:
	子进程的全局变量>>> 0
	主进程的全局变量>>> 100


进程对象属性

#代码示例:
from multiprocessing import Process Lock

def dask(name):
    print("%s的子进程"%name)

if __name__ == '__main__':
    p = Process(target=dask, args=('jason',))
    p.start()
    p.join()
    print("子进程的ID是>>>", p.pid)
    print("子进程的名字是>>>", p.name)
    print("主进程执行完毕!")
    
   """
进程号如何查看
	windows: 			tasklist结果集中PID
	mac:					ps -ef
"""
#查看进程号的方法
1.current_process函数
  	from multiprocessing import Process, current_process
    current_process().pid
 	# 获取进程号的用处之一就是可以通过代码的方式管理进程
  	windows  			taskkill关键字
    mac/linux  		kill关键字
2.os模块
  	os.getpid()  # 获取当前进程的进程号
    os.getppid()  # 获取当前进程的父进程号
    

僵尸进程与孤儿进程

# 僵尸进程
	 '为什么主进程默认需要等待子进程结束才会结束'
  所有的子进程在运行结束之后都会变成僵尸进程(死了没死透)
  还保留着pid和一些运行过程的中的记录便于主进程查看(短时间保存)
  这些信息会被主进程回收(僵尸彻底死了)
  	1.主进程正常结束
    2.调用join方法
    
# 孤儿进程
	# 子进程存活着 父进程意外死亡
  子进程会被操作系统自动接管(儿童福利院)

守护进程

'主进程执行结束,由该主进程创建的子进程必须跟着结束'
# 代码示例
from multiprocessing import Process
import time
def dask(name):
    print("%s开始执行子进程" % name)
    time.sleep(2)
    print("%s结束执行子进程" % name)

if __name__ == '__main__':
    p = Process(target=dask, args=('jason',))
    p.daemon = True
'一定要在p.start()前设置p为守护进程,禁止p创建子进程,并且父进程代码执行结束,p即终止运行'
    p.start()
    print("主进程执行完毕!")
    

互斥锁

# 代码示例
import json
from multiprocessing import Process
import time
import random


# 查票
def search(name):
    with open(r'ticket_data.json', 'r', encoding='utf8') as f:
        data = json.load(f)
    print(f'{name}查询当前余票:%s' % data.get('ticket_num'))


# 买票
def buy(name):
    '''
    点击买票是需要再次查票的 因为期间其他人可能已经把票买走了
    '''
    # 1.查票
    with open(r'ticket_data.json', 'r', encoding='utf8') as f:
        data = json.load(f)
    time.sleep(random.randint(1, 3))
    # 2.判断是否还有余票
    if data.get('ticket_num') > 0:
        data['ticket_num'] -= 1
        with open(r'ticket_data.json', 'w', encoding='utf8') as f:
            json.dump(data, f)
        print(f'{name}抢票成功')
    else:
        print(f'{name}抢票失败 没有余票了')


def run(name, mutex):
    search(name)
    mutex.acquire()  # 抢锁
    buy(name)
    mutex.release()  # 放锁


# 模拟多人同时抢票
if __name__ == '__main__':
    mutex = Lock()
	'互斥锁需要产生在主进程 然后再交给多个子进程'
    for i in range(1, 10):
        p = Process(target=run, args=('用户:%s' % i,mutex))
        p.start()

'''当多个进程操作同一份数据的时候会造成数据的错乱!!!
这个时候需要加锁处理(互斥锁)
	将并发变成串行 牺牲了效率但是保证的数据的安全
 
互斥锁并不能轻易使用 容易造成死锁现象
互斥锁只在处理数据的部分加锁 不能什么地方都加 严重影响程序的效率'''
        
        

posted @ 2022-04-19 18:14  洛阳城门听风雨  阅读(50)  评论(0)    收藏  举报