python多进程基础详解

作者:七层汉堡王 时间:2021-07-14 10:06:52 

进程

什么是进程
进程指的是一个程序的运行过程,或者说一个正在执行的程序
所以说进程一种虚拟的概念,该虚拟概念起源操作系统

一个CPU 同一时刻只能执行一件事

开启一个进程


from  multiprocessing import Process
import time
def task(name):
   print('%s is running'%name)
   time.sleep(3)
   print('%s is done'%name)
# 开启子进程的操作必须放到
# if __name__ == '__main__'的子代码中
# 子进程不会再次加载
if __name__ == '__main__':
   p=Process(target=task,args=('小王',))
   # p=Process(target=task,kwargs={'name':'小王'})
   # print(p)
   p.start()
   # 主进程只是向操作系统发送了一个开启子进程的信号
   # p.start()
   # 1.操作系统先申请内存空间
   # 2.把主进程的数据拷贝到子进程里面
   # 3.调用cup才能运行里面的代码
   # 创造进程的开销大
   print('主')

python多进程基础详解

JOIN方法

当前进程jion别的进程。当前进程就会等到别的进程执行完毕了才会继续开始往下执行

python多进程基础详解


from multiprocessing import Process
import time

def task(name, n):
   print('%s is running' % name)
   time.sleep(n)
   print('%s is done' % name)

if __name__ == '__main__':
   start = time.time()
   p_l = []
   for i in range(1, 4):
       p = Process(target=task, args=('小王%s' % i, i))
       p_l.append(p)
       p.start()
   # 主进程等待子进程
   for p in p_l:
       p.join()
   print('主', (time.time() - start))

进程之间空间隔离


from multiprocessing import  Process
# 这个n是主进程里面的值
n = 100
def task():
   global n
   # 改的是子进程里面的全局变量
   # 主进程里面没有改
   n = 0
if __name__ == '__main__':
   p=Process(target=task)
   p.start()
   p.join()
   print(n)

python多进程基础详解

进程的常用方法

current_process 查看pid(进程id)


# 1. 进程pid:每一个进程在操作系统内都有一个唯一的id号,称之为pid
from multiprocessing import Process, current_process
import time

def task():
   print('%s is running' % current_process().pid)
   time.sleep(3)
   print('%s is done' % current_process().pid)

# 开启子进程的操作必须放到
# if __name__ == '__main__'的子代码中
# 子进程不会再次加载
if __name__ == '__main__':
   p = Process(target=task)
   p.start()
   print('主', current_process().pid)

python多进程基础详解

os.getpid() 查看进程id


# os模块也可以
from multiprocessing import Process, current_process
import time, os

def task():
   print('%s is running 爹是%s' % (os.getpid(), os.getppid()))
   time.sleep(3)
   print('%s is done爹是%s' % (os.getpid(), os.getppid()))

# 开启子进程的操作必须放到
# if __name__ == '__main__'的子代码中
# 子进程不会再次加载
if __name__ == '__main__':
   p = Process(target=task)
   p.start()
   # 谁把主进程创造出来的
   #   用pycharm就是pycharm创造的
   print('主%s爹是%s' % (os.getpid(), os.getppid()))

python多进程基础详解

进程其他方法和属性


from multiprocessing import Process,current_process
import time,os
def task():
   print('%s is running 爹是%s'%(os.getpid(),os.getppid()))
   time.sleep(30)
   print('%s is done爹是%s'%(os.getpid(),os.getppid()))
# 开启子进程的操作必须放到
# if __name__ == '__main__'的子代码中
# 子进程不会再次加载
if __name__ == '__main__':
   p=Process(target=task)
   p.start()
   # 谁把主进程创造出来的
   # 用pycharm就是pycharm创造的
   # 进程的名字
   print(p.name)
   # 杀死子进程
   p.terminate()
   # 需要时间
   time.sleep(0.1)
   #  判断子进程是否存活
   print(p.is_alive())
   print('主%s爹是%s'%(os.getpid(),os.getppid()))

python多进程基础详解

守护进程

本质就是一个"子进程",该"子进程"的生命周期<=被守护进程的生命周期
当被守护的进程执行完了。它也会被杀死


# 主进程运行完了,子进程没有存在的意义
# 皇帝和太监不是同生,但是是同死
from  multiprocessing import Process
import time
def task(name):
   print('%s活着'%name)
   time.sleep(3)
   print('%s正常死亡'%name)
if __name__ == '__main__':
   p1=Process(target=task,args=('老太监',))
   # 声明子进程为守护进程
   p1.daemon = True
   p1.start()
   time.sleep(1)
   print('皇帝正在死亡')

python多进程基础详解

互斥锁

进程之间内存空间互相隔离,怎样实现共享数据
进程之间内存数据不共享,但是共享同一套文件系统,所以访问同一个文件,是没有问题的,
而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理


'''
抢票
   查票
   购票
互斥锁:
   在程序中进行加锁处理
   必须要释放锁下一个锁才能获取,所以程序在合适的时候必须要有释放锁
所以用文件来处理共享数据
   1.速度慢
   2.必须有互斥锁
'''
import json
import time,random
from multiprocessing import Process,Lock
# 查票
def search(name):
   with open('db.json','rt',encoding='utf-8')as f:
       dic = json.load(f)
   # 模拟查票时间
   time.sleep(1)
   print('%s 查看到余票为 %s'%(name,dic['count']))
# 购票
# 第二个get子进程不会是第一个get子进程修改后count的结果
# 加互斥锁,把这一部分并发变成串行,
# 但是牺牲了效率,保证了数据安全
def get(name):
   with open('db.json','rt',encoding='utf-8')as f:
       dic = json.load(f)
   if dic['count']>0:
       dic['count']-=1
       time.sleep(random.randint(1,3))
       with open('db.json', 'wt', encoding='utf-8')as f:
           json.dump(dic,f)
           print('%s 购票成功'%name)
   else:
       print('%s 查看到没有票了'%name)
def task(name,mutex):
   # 并发
   search(name)
   # 串行
   # 加互斥锁
   mutex.acquire()
   get(name)
   # 释放互斥锁
   mutex.release()
# if __name__ == '__main__':
#     for i in range(10):
#         p=Process(target=task,args=('路人%s'%i,))
#         p.start()
#         #  join只能将进程的任务整体变成串行
#         # 互斥锁可以局部串行
#         p.join()
#         # 数据安全,是指读的时候无所谓,写的(改的)时候必须安全
#         # 写的时候是串行,读的时候并发
# 加锁
if __name__ == '__main__':
   # 主进程加锁
   mutex=Lock()
   for i in range(10):
       # 锁传入子进程
       p=Process(target=task,args=('路人%s'%i,mutex))
       p.start()
       #  join只能将进程的任务整体变成串行
       # 互斥锁可以局部串行
       # p.join()
       # 数据安全,是指读的时候无所谓,写的(改的)时候必须安全
       # 写的时候是串行,读的时候并发

db.json 中只有10张票。如果没有加锁。则可能会出现票呗多卖的情况
python多进程基础详解

进程间通信(IPC机制)


'''
速度快
锁问题解决
ipc机制
   进程彼此之间互相隔离,要实现进程间通信(IPC),
   multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的
   共享内存空间
   队列=管道+锁
'''
from  multiprocessing import Queue
# 占用的内存,最好小数据,消息数据,下载地址
# Queue(限制队列里面的个数)
# 先进先出
q=Queue(3)
# 添加
q.put('a')
q.put('b')
q.put({'x':2})
print('篮子满了')
# 队列满了,相当于锁了
# q.put({'x':2})
# 提取
print(q.get())
print(q.get())
print(q.get())
# # 队列为空,等待加入,也会阻塞,相当于锁了
print('队列为空')
print(q.get())

队列被取完了 后面的q.get() 会阻塞直到有新的元素。所以程序不会结束

python多进程基础详解

JoinableQueue 来实现生产消费者

JoinableQueue#task_done()方法当队列里面没有元素会结束线程


'''
小王和小周每人生产10分包子和土豆丝
小戴和小杨一直吃,当队列里面没有食物时。终结进程
'''
import time, random
from multiprocessing import Process, JoinableQueue

def producer(name, food, q):
   for i in range(10):
       res = '%s%s' % (food, i)
       # 模拟生产数据的时间
       time.sleep(random.randint(1, 3))
       q.put(res)
       print('厨师%s生成了%s' % (name, res))

def consumer(name, q):
   while True:
       # 订单都没了还在等,队列里面空了
       res = q.get()
       # 模拟处理数据的时间
       time.sleep(random.randint(1, 3))
       print('吃货%s吃了%s' % (name, res))
       # 1每次完成队列取一次,往q.join() ,取干净了q.join()运行完
       q.task_done()

# 多个生产者和消费者
if __name__ == '__main__':
   q = JoinableQueue()
   # 生产者
   p1 = Process(target=producer, args=('小王', '包子', q))
   p3 = Process(target=producer, args=('小周', '土豆丝', q))
   # 消费者
   c1 = Process(target=consumer, args=('小戴', q))
   c2 = Process(target=consumer, args=('小杨', q))
   # #3.守护进程的作用: 主进程死了,消费者子进程也跟着死
   #     #把消费者变成守护进程
   c1.daemon = True
   c2.daemon = True
   p1.start()
   p3.start()
   c1.start()
   c2.start()
   p1.join()
   p3.join()
   # 2消费者task_done给q.join()发信号
   q.join()
   print('主')
   # 生产者运行完?1,2
   # 消费者运行完?1,2

当队列为空时,不会傻傻等待而是结束进程

python多进程基础详解

来源:https://blog.csdn.net/weixin_39313241/article/details/120607154

标签:python,多进程,基础
0
投稿

猜你喜欢

  • 浅析Python的命名空间与作用域

    2022-11-27 04:19:04
  • asp函数遍历文件夹代码

    2010-06-21 10:38:00
  • Python把对应格式的csv文件转换成字典类型存储脚本的方法

    2022-07-08 08:39:06
  • 如何动态产生变量?

    2009-11-18 16:33:00
  • Python Pandas中布尔索引的用法详解

    2023-11-04 08:37:45
  • PHP实现批量生成App各种尺寸Logo

    2023-07-23 03:59:59
  • 详解Python如何实现尾递归优化

    2023-11-13 04:20:06
  • VS 2010 Ultimate架构代码探索

    2010-05-02 20:38:00
  • 下拉列表两级连动的新方法(二)

    2009-06-04 18:22:00
  • Python使用当前时间、随机数产生一个唯一数字的方法

    2022-02-10 14:57:07
  • Python实现图像增强

    2022-07-08 10:50:50
  • 使用Python实现企业微信通知功能案例分析

    2022-12-26 05:03:48
  • python多个模块py文件的数据共享实例

    2022-02-24 23:33:39
  • 详解pandas.DataFrame中删除包涵特定字符串所在的行

    2023-08-23 23:37:45
  • 事件检测

    2009-04-11 18:03:00
  • 如何在不同版本的SQL Server中存储数据

    2009-01-15 13:06:00
  • NumPy 与 Python 内置列表计算标准差区别详析

    2023-08-28 20:01:19
  • 全局字体最佳实践

    2009-08-13 14:37:00
  • 浅谈PyQt5中异步刷新UI和Python多线程总结

    2023-08-22 01:37:18
  • CSS编写过程中常见的10个错误

    2008-05-29 12:49:00
  • asp之家 网络编程 m.aspxhome.com