进程和线程主要是用来提高效率和分担任务的,但他们还有待完善,接下来我将具体介绍进程间的通信隔离与线程间的资源争夺,以及如何解决这两个问题。
1. 进程相互通信
1.1. 进程间的通信隔离
管理器用来通信,代理(公共服务器)来操作。
1.2. 通信解决办法
import multiprocessing
mg = multiprocessing.Manager() # 创建一个公共服务器进程,返回与主进程的代理
var = 10
def func(list1):
global var
var += 1
print('func:',var)
list1.append(var)
li = mg.list() # 开辟一个列表空间,多个进程可以一起使用的
p1 = multiprocessing.Process(target=func, args=(li,))
p1.start()
p1.join()
print('outer:', var) # 不通过公共服务器,outputs:outer: 10
print('outer:', li) # 通过公共服务器,outputs:outer: [11]
multiprocessing.Manager()
:创建一个公共服务器进程,返回与主进程的代理,是进程间通信的常用解决方案,通过公共空间来实现进程间的通信。
2. 线程相互通信
2.1. 线程共享变量
对于线程而言,它们始终在一个进程当中,因此共享同一个内存空间,因此可以访问主进程中的数据。
"""线程没有通信隔离,不需要公共服务器"""
import threading
var = 10
def func():
global var
var += 1
print('func:',var)
return var
t1 = threading.Thread(target=func)
t1.start()
t1.join()
print('outer:',var)
2.2. 线程资源争夺问题
2.2.1. 线程资源争夺问题
当计算量过大时,会出现资源错误,因为CPU计算式多条指令,组合运行的,所以在运行过程中如果插入其它指令,就会造成不可预见的效果。
2.2.2. 互斥锁
对于特殊资源,可以用锁来保护资源,确保每次操作的完整性。
"""
线程有的时候运行会错乱:(线程争夺)
但用互斥锁会耗费时间,所以使用的比较少
"""
import threading
var =100
lock = threading.Lock() # 互斥锁
def func1():
global var
for i in range(100000):
lock.acquire() # 上锁
var += 1
lock.release() # 解锁
def func2():
global var
for i in range(100000):
lock.acquire() # 上锁
var -= 1
lock.release() # 解锁
t1 = threading.Thread(target=func1)
t2 = threading.Thread(target=func2)
t1.start()
t2.start()
t1.join()
t2.join()
print(var)
3. 队列
3.1. 队列概念
队列:先进先出
3.2. 队列的实现
import queue
:导入队列模块
q=queue.Queue(4)
:设置的队列长度,这里表示设置4,当存放数量大于队列长度时,会发生阻塞。
q.put('a')
:存入a,b、c、d与a相同,当到e时,会报错,因为超过了队列长度。
q.get()
:依次取出队列里的数,当取数大于队列长度时,会发生阻塞。
q.empty()
:可通过该指令查看当前队列是否为空。
q.full()
:可通过该指令查看当前队列是否满。
q.qsize()
:可通过该指令查看当前队列的数量。
4. 生产者与消费者模型
4.1. 基本概念
生产者和消费者模型:
queue.Queue()线程队列只在主进程里面,不能使用在进程和进程的交互中
"""
生产者和消费者模型:
queue.Queue()线程队列只在主进程里面,不能使用在进程和进程的交互中
"""
import threading
import queue
import time
q = queue.Queue(4) # 设置线程队列长度为4
class Consumer(threading.Thread): # 继承了线程类
# 消费者
def __init__(self,q):
super().__init__() # 让Consumer成为一个线程对象,重写线程类的init方法
self.queue = q
def run(self):
while True:
# 消费者逻辑 不需要考虑生产者 只需要获取队列中的任务即可
res = self.queue.get() # 获取任务
print(f'消费了数据{res*100}')
class Producer(threading.Thread):
# 生产者
def __init__(self,q):
super().__init__()
self.queue = q
def run(self):
# 生产者逻辑 不需要考虑消费者,只需要往队列中添加任务
import random
while True:
time.sleep(1)
res = random.randint(1,100)
print(f'生产了数据{res}')
self.queue.put(res) # 提交任务
pr = Producer(q)
cu = Consumer(q)
pr.start()
cu.start()
生产者和消费者模型:
multiprocessing.Queue该进程队列能使用在进程和进程的交互中
"""
生产者和消费者模型:
multiprocessing.Queue该进程队列能使用在进程和进程的交互中
"""
import multiprocessing
import queue
import time
q = multiprocessing.Queue(4) # 设置进程队列长度为4
class Consumer(multiprocessing.Process): # 继承了进程类
# 消费者
def __init__(self,q):
super().__init__() # 让Consumer成为一个进程对象,重写进程类的init方法
self.queue = q
def run(self):
while True:
# 消费者逻辑 不需要考虑生产者 只需要获取队列中的任务即可
res = self.queue.get() # 获取任务
print(f'消费了数据{res*100}')
class Producer(multiprocessing.Process):
# 生产者
def __init__(self,q):
super().__init__()
self.queue = q
def run(self):
# 生产者逻辑 不需要考虑消费者,只需要往队列中添加任务
import random
while True:
time.sleep(1)
res = random.randint(1,100)
print(f'生产了数据{res}')
self.queue.put(res) # 提交任务
pr = Producer(q)
cu = Consumer(q)
pr.start()
cu.start()
文章到这里就结束了!希望大家能多多支持Python(系列)!六个月带大家学会Python,私聊我,可以问关于本文章的问题!以后每天都会发布新的文章,喜欢的点点关注!一个陪伴你学习Python的新青年!不管多忙都会更新下去,一起加油!
Editor:Lonelyroots
网友评论