创建进程

    在python中提供了一个multiprocessing模块可以帮助我们使用多进程解决问题。在multiprocessing
模块中有一个类Process。
    from multiprocessing import Process

'''
group=None, 为日后开发新功能准备
target=None, 目标任务
name=None, 进程的姓名
args=(), 目标任务需要的位置参数
kwargs={}, 目标任务需要的字典参数
daemon=None):默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
'''
#方法介绍
p.start()#开启进程,使用run()方法
p.run()#进程启动时运行的方法是它去调用target指定的目标
p.terminate()#强制终止进程,不会进行清理操作
p.is_alive()#判断进程是否存活
p.join([timeout])#让在join方法之后的进程等待,直到p进程运行结束 """
强调:不同的操作系统创建进程的要求不一样
在windows中创建进程是以导入模块的方式进行 所以创建进程的代码必须写在__main__子代码中
否则会直接报错 因为在无限制创建进程
在linux和mac中创建进程是直接拷贝一份源代码然后执行 不需要写在__main__子代码中
"""

第一种方法

    from multiprocessing import Process
import time def test():
print('=======>')
time.sleep(3)
print('=======>') def test1(name):
print(f'{name}')
time.sleep(3)
print('=======>') if __name__ == '__main__':
p = Process(target=test)
# p = Process(target=test1, args=('春游去动物园',))
p.start()
print('主')

第二种方法

    from multiprocessing import Process

    class Test(Process):
def __init__(self,name):
super().__init__()
self.name = name def run(self):
print(self.name) if __name__ == '__main__':
p = Test('test')
p.start()
print('主')
#自定义类主要是改写他的run()方法,run()方法在调用start()方法时一定会被调用

join

'''join让主进程等待子进程结束之后,再执行主进程。'''

    from multiprocessing import Process
import time
def task(name):
print(f"{name} is running")
time.sleep(2)
print(f"{name} is gone")
if __name__ == "__main__":
p = Process(target=task, args=("春游去动物园",)) # 创建一个进程对象
p.start()
# p.join()
print(111)
print("主开始") 111
主开始
春游去动物园 is running
春游去动物园 is gone from multiprocessing import Process
import time
def task(name):
print(f"{name} is running")
time.sleep(2)
print(f"{name} is gone")
if __name__ == "__main__":
p = Process(target=task, args=("春游去动物园",)) # 创建一个进程对象
p.start()
p.join()
print(111)
print("主开始") 春游去动物园 is running
春游去动物园 is gone
111
主开始
'''一般而言,主程序中如果单为一句print,则优先执行print语句(如果执行语句够多,则可见子进程执行)'''

    from multiprocessing import Process
import time def task(name):
print(f"{name} is running")
time.sleep(2)
print(f"{name} is gone") if __name__ == "__main__":
p = Process(target=task,args=("春游去动物园",)) # 创建一个进程对象
p.start()
# p.join()
print(111)
time.sleep(0.5)
print("主开始") 111
春游去动物园 is running
主开始
春游去动物园 is gone
'''如果程序中有连续多个join函数,则只有最先的join是起作用的'''
from multiprocessing import Process
import time def task(name,sec):
print(f"{name} is running")
time.sleep(sec)
print(f"{name} is gone") if __name__ == "__main__":
start_time = time.time()
p = Process(target=task,args=("常",3)) # 创建一个进程对象
p1 = Process(target=task,args=("辛",5)) # 创建一个进程对象
p2 = Process(target=task,args=("王",1)) # 创建一个进程对象 p.start()
p1.start()
p2.start() # join只针对主进程,如果join下面多次join他是不阻塞的
p.join()
p1.join()
p2.join() print(f"主{time.time()-start_time}") 辛 is running
常 is running
王 is running
王 is gone
常 is gone
辛 is gone
主5.103694438934326 # 注:如果不是连续多个,比如这样:
from multiprocessing import Process
import time def task(name,sec):
print(f"{name} is running")
time.sleep(sec)
print(f"{name} is gone") if __name__ == "__main__":
start_time = time.time()
p = Process(target=task,args=("常",3)) # 创建一个进程对象
p1 = Process(target=task,args=("辛",5)) # 创建一个进程对象
p2 = Process(target=task,args=("王",1)) # 创建一个进程对象 p.start()
p.join()
p1.start()
p1.join()
p2.start()
p2.join() print(f"主{time.time()-start_time}") 常 is running
常 is gone
辛 is running
辛 is gone
王 is running
王 is gone
主9.267089128494263
# 这样就会先执行p进程,再执行p1进程,再执行p2进程

进程间数据默认隔离

    from multiprocessing import Process

    a=100
def test():
global a
a=50
print(a) # 50 if __name__ == '__main__':
p = Process(target=test)
p.start()
print(a) # 100 100
50

进程对象属性和方法

查看进程号

    '''第一种current_process函数'''
from multiprocessing import Process,current_process
a=100
def test():
global a
a=50
print(a) # 50
if __name__ == '__main__':
p = Process(target=test)
p.start()
print(current_process()) # 获取进程的名称 <_MainProcess name='MainProcess' parent=None started>
print(current_process().pid) # 获取进程的id 8560
print(a) # 100 '''第二种os模块'''
import os
from multiprocessing import Process,current_process
a=100
def test():
global a
a=50
print(a) # 50
if __name__ == '__main__':
p = Process(target=test)
p.start()
print(os.getpid()) # 9748 获取当前进程的进程号
print(os.getppid()) # 5220 获取当前进程的父进程号
print(a) # 100 os.getpid() # 获取当前进程的进程号
os.getppid() # 获取当前进程的父进程号

杀死子进程

    terminate():不管任务是否完成,立即终止子进程
from multiprocessing import Process,current_process
import time
a=100
def test():
global a
time.sleep(3)
a=50
print(a)
if __name__ == '__main__':
p = Process(target=test)
p.start()
p.terminate()
print(a)
100

判断子进程是否存活

    is_alive():判断进程子进程是否还在活着
from multiprocessing import Process,current_process
import time
a=100
def test():
global a
time.sleep(3)
a=50
print(a)
if __name__ == '__main__':
p = Process(target=test)
p.start()
print(p.is_alive()) # True
p.terminate() # 杀死进程
time.sleep(0.5)
print(p.is_alive()) # False

僵尸进程与孤儿进程

僵尸进程

  僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子
进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
'''
僵死进程:子进程退出后,会将该进程的重型资源释放掉(cpu,内存,打开的文件),子进程的进
程描述符仍然保存在系统中,比如pid。
'''
所有的子进程在运行结束之后都会变成僵尸进程(死了没死透)
程序正常结束才会产生僵尸进程,如果强制关闭父进程,操作系统会把父进程已经运行结束的子进程全部
删除,也就不会产生僵尸进程了。
僵尸进程的危害:
系统的pid号是有限的,僵尸进程保留的信息如果一直不被释放,一直累计会导致没有可用的pid号而
导致系统不能产生新的进程

孤儿进程

   孤儿进程(无害):一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿
进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
'''
子进程存活着 父进程意外死亡
子进程会被操作系统自动接管(儿童福利院)
'''

守护进程

    正常情况下,主进程默认等待子进程调用结束之后结束
守护进程在主进程执行代码结束后,自动终止
"""
守护即死活全部参考守护的对象
对象死立刻死
"""
主进程代码运行完毕,守护进程就会结束
from multiprocessing import Process
import os, time def task():
print("进程%s开启" % os.getpid())
time.sleep(10)
print("进程%s结束" % os.getpid()) if __name__ == '__main__':
p = Process(target=task,daemon=True) # 在创建进程时也可以设置daemon,True为开启守护进程,默认为False。
#p.daemon = True # 这一行代码会把子进程变成守护代码,主进程运行完,子进程也就运行完了,不会打印进程结束的那行代码
p.start()
print("主:%s" % os.getpid())
time.sleep(3) 主:6812
进程10096开启

互斥锁

互斥锁的概念

    互斥锁: 对共享数据进行锁定,保证同一时刻只能有一个线程去操作。

    注意:
互斥锁是多个线程一起去抢,抢到锁的线程先执行,没有抢到锁的线程需要等待,等互斥锁使用完释放
后,其它等待的线程再去抢这个锁。 互斥锁的意思就是互相排斥,我们可以把多个进程比喻多个人,互斥锁的工作原理就是多个人去争抢共同
的一个资源:如多个人要上同一个卫生间,一个人抢到卫生间后上一把锁,其他人都有外面等着,等到这个人
完成后解锁后,其他人又可以去争夺。所以互斥锁的原题,就是把某一功能并发改串行,虽然降低了效率,但
保证了数据安全不错乱。
"""
锁相关知识
行锁:针对行数据加锁 同一时间只能一个人操作
表锁:针对表数据加锁 同一时间只能一个人操作
锁的应用范围很广 但是核心都是为了保证数据的安全!!!
"""

互斥锁的使用

    from multiprocessing import Process,Lock
# 创建锁
mutex = Lock() # 上锁
mutex.acquire() ...这里编写代码能保证同一时刻只能有一个线程去操作, 对共享数据进行锁定... # 释放锁
mutex.release() 注意点:
acquire和release方法之间的代码同一时刻只能有一个线程去操作
如果在调用acquire方法的时候 其他线程已经使用了这个互斥锁,那么此时acquire方法会堵塞,直到
这个互斥锁释放后才能再次上锁。

互斥锁与join()的区别

    互斥锁与join()的区别:
大前提:二者的原理都是一样,都是将并发变成串行,从而保证有序 区别一:join是按照人为指定的顺序执行,而互斥锁是所有进程平等地竞争,谁先抢到谁先执行。 区别二:互斥锁可以让一部分代码(修改共享数据的代码)串行,而join只能将代码整体串行。

抢票小案例

    # db.json文件中的内容为{"count": 100}
from multiprocessing import Process, Lock
import json, time
import random def search(name):
dic = json.load(open('db.json', 'r', encoding='utf-8'))
time.sleep(random.randint(0, 2)) # 模拟网络延迟
print('%s查到剩余的票数为%s张' % (name, dic['count'])) def get(name):
dic = json.load(open('db.json', 'r', encoding='utf-8'))
time.sleep(0.3) # 模拟网络延迟
if dic['count'] > 0:
time.sleep(0.1) # 模拟网络延迟
print('%s成功买到了剩下的第%s票' % (name, dic['count']))
dic['count'] -= 1
json.dump(dic, open('db.json', 'w', encoding='utf-8')) def rob_ticket(name, lock):
search(name)
with lock: # 相当于获得了lock.acquire(),执行代码体完,自动执行lock.release()
get(name) if __name__ == '__main__':
lock = Lock()
for i in range(10):
name = '路人%s' % i
p = Process(target=rob_ticket, args=(name, lock))
p.start() 执行结果:
路人0查到剩余的票数为5张
路人1查到剩余的票数为5张
路人8查到剩余的票数为5张
路人7查到剩余的票数为5张
路人9查到剩余的票数为5张
路人0成功买到了剩下的第5票
路人1成功买到了剩下的第4票
路人2查到剩余的票数为5张
路人4查到剩余的票数为5张
路人3查到剩余的票数为5张
路人6查到剩余的票数为5张
路人8成功买到了剩下的第3票
路人7成功买到了剩下的第2票
路人5查到剩余的票数为5张
路人9成功买到了剩下的第1票

最新文章

  1. Ubuntu14.04运行行roscore错误
  2. TestLink测试软件安装条件检查不通过的解决方案
  3. cf 106C
  4. Data storage on the batch layer
  5. SQLSERVER吞噬内存解决记录
  6. python_遇到问题
  7. 未在本地计算机上注册&quot;Microsoft.ACE.OLEDB.12.0&quot;提供程序
  8. wifi 攻破
  9. Oracle WorkFlow(工作流)(一)
  10. C# mvc 前端调用 redis 缓存的信息
  11. 学习笔记CB005:关键词、语料提取
  12. 阶乘函数(factorial)——结果在整型范围内的阶乘计算
  13. python 作用域
  14. ORACLE 计算时间相减间隔
  15. python 将文件大小转换为human readable 的大小表示
  16. 历届试题 大臣的旅费-(树的直径+dfs)
  17. c#按照指定长度切分字符串
  18. ArcGIS Desktop Python add-ins 共享和安装插件
  19. RPC簡介
  20. Linux OpenCV 静态链接错误

热门文章

  1. github 编写README时常用的写法
  2. Leetcode26——删除有序数组中的重复项(双指针法)
  3. apollo规划控制视频-12basic motion planning and overview
  4. python模块 | 随机数模块—random模块
  5. uniapp-npm install 进入版本后 优先运行全局安装,在HBuilder X终端输入 npm install 点击回车
  6. 左手Cookie“小甜饼”,右手Web Storage
  7. 《每周一点canvas动画》——圆周运动
  8. Leetcode1/242/383-HashMap常用方法以及遍历排序方式
  9. Android 动态控制OptionMenu的显示与隐藏
  10. Bitmap图片的处理