文章目录
一、multiprocessing内置消息队列
消息队列是先进先出的,用于进行进程之间信息传递的。
from multiprocessing import Queue
q = Queue(3) # 设置队列长度
q.put(123) # 向队列添加元素
q.put(1234)
print("队列是否填满:",q.full()) # 判断队列是否填满
q.put(12345)
print("队列是否填满:",q.full())
print(q.get()) # 从队列取出元素
print("队列是否为空:",q.empty()) # 判断队列是否为空
print(q.get())
print(q.get_nowait()) # 从队列取一个元素,如果队列为空,则报错
print("队列是否为空:",q.empty())
print(q.get_nowait()) # 从队列取一个元素,如果队列为空,则报错
full()
empty()
get_nowait()
三个方法不能在并发的情况下精确使用。
二、IPC机制
IPC机制主要是用来处理以下几种情况的:
- 主进程与子进程之间的信息交互
- 子进程与子进程之间的信息交互
其本质是不同内存空间的进程数据交互
from multiprocessing import Process, Queue
def dask(q, cont):
print("子进程%d获取了一个数据信息:%s"%(cont, q.get()))
def se(q,cont , txt):
q.put(txt)
print("子进程%d存放了一个数据信息:%s"%(cont, txt))
if __name__ == '__main__':
q = Queue(5)
p1 = Process(target=dask, args=(q, 1))
p2 = Process(target=se, args=(q, 2, "hello"))
p2.start()
p1.start()
三、生产者消费者模型
生产者指生成数据的部分
消费者指使用数据的部分
生产者消费者模型主要怕用于解决生产和使用之间的关系,生产过快或者消费过快都是不行的,此时便需要一个平衡,所以产生了生产者消费者模型。
from multiprocessing import Process, Queue
import time
def produce(q, num, commodity):
for i in range(8):
q.put(commodity + str(i))
time.sleep(1)
print("生产商%d生产了%s%d"%(num, commodity, i))
def consume(q, num):
time.sleep(2)
while True:
if not q.empty():
time.sleep(1)
comm = q.get()
print("消费者%d消费了%s"%(num, comm))
else:
print("没有商品了,消费者%d只剩下钱了"%num)
return
if __name__ == '__main__':
q = Queue()
p1 = Process(target=produce, args=(q, 1, "苹果手机"))
p2 = Process(target=produce, args=(q, 2, "苹果手机"))
c1 = Process(target=consume, args=(q, 1))
c2 = Process(target=consume, args=(q, 2))
p1.start()
p2.start()
c1.start()
c2.start()
print("生产着消费者模型演示")
四、线程
1.线程是什么?
进程是资源单位,而线程是进程中的执行单位,一个进程中可以有多个线程,一个进程至少有一个线程。
- 线程的建立比进程消耗的资源少
- 进程仅仅是在内存中开辟一块空间(提供线程工作所需的资源)
- 线程真正被CPU执行,线程需要的资源跟所在进程的要
2.线程创建
Thread类中自带name属性,不可以修改name,一旦修改会报错,name值的含义为线程名-线程数
2.1 使用Thread创建
from threading import Thread
def desk(content):
print("线程%d开启了"%content)
print("线程%d结束了"%content)
t1 = Thread(target=desk, args=(1, ))
t2 = Thread(target=desk, args=(2, ))
t3 = Thread(target=desk, args=(3, ))
t1.start()
t2.start()
t3.start()
2.2使用类来创建
from threading import Thread
class MyThread(Thread):
def __init__(self, num):
self.num = num
super().__init__()
def run(self):
print("线程%d开启了" % self.num)
print("线程%d结束了"% self.num)
t1 = MyThread(1)
t2 = MyThread(2)
t1.start()
t2.start()
3.线程数据
一个进程内的多个线程数据是共享的
4.线程同步
线程开启后默认都是异步处理的,此时使用join方法可以让投个线程变为同步运行。
from threading import Thread
import time
def desk(content):
date = time.strftime("%Y %m %d %X")
print(f"线程%d开启了,此时时间为:{date}"%content)
time.sleep(content)
date1 = time.strftime("%Y %m %d %X")
print(f"线程%d结束了,此时时间为:{date1}"%content)
t1 = Thread(target=desk, args=(1, ))
t2 = Thread(target=desk, args=(2, ))
t3 = Thread(target=desk, args=(3, ))
t3.start()
t3.join()
t2.start()
t1.start()
5.线程的属性与方法
5.1active_count
active_count()方法是获取当前开启的所有线程数量
from threading import Thread, active_count
import time
def desk(content):
date = time.strftime("%Y %m %d %X")
print(f"线程%d开启了,此时时间为:{date}"%content)
time.sleep(3)
date1 = time.strftime("%Y %m %d %X")
print(f"线程%d结束了,此时时间为:{date1}"%content)
t1 = Thread(target=desk, args=(1, ))
t2 = Thread(target=desk, args=(2, ))
t3 = Thread(target=desk, args=(3, ))
t3.start()
t2.start()
t1.start()
print("开启的线程数:",active_count())
5.2 获取线程名字
获取子线程名字时为子线程名字-子线程数
获取主线程名字时为MainThread
使用current_thread方法获取
from threading import Thread, active_count, current_thread
import time
def desk(content):
date = time.strftime("%Y %m %d %X")
print(f"线程%d开启了,此时时间为:{date}"%content)
time.sleep(3)
print("子线程名字:",current_thread().name)
date1 = time.strftime("%Y %m %d %X")
print(f"线程%d结束了,此时时间为:{date1}"%content)
t1 = Thread(target=desk, args=(1, ))
t2 = Thread(target=desk, args=(2, ))
t3 = Thread(target=desk, args=(3, ))
t3.start()
t2.start()
t1.start()
print("开启的线程数:",active_count())
print("主线程名字", current_thread().name)
使用self.name获取
from threading import Thread
class MyThread(Thread):
def __init__(self, num):
self.num = num
super().__init__()
def run(self):
print("线程%d开启了" % self.num)
print("线程名字:", self.name)
print("线程%d结束了"% self.num)
t1 = MyThread(1)
t2 = MyThread(2)
t1.start()
t2.start()
6.守护线程
守护线程在被守护线程结束后会直接结束。
守护线程通过设置daemon 来实现,设置守护线程需要在要设置为守护线程的启动之前完成。
from threading import Thread
import time
def desk(content):
print(f"线程%d开启了"%content)
time.sleep(3)
print(f"线程%d结束了"%content)
t1 = Thread(target=desk, args=(1, ))
t1.daemon = True
t1.start()
print("主线程结束")
五、GIL全局解释器锁
官方文档
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly
because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)
GIL只存在于CPython解释器中,不是python的特征
GIL是一把互斥锁用于阻止同一个进程下的多个线程同时执行
原因是因为CPython解释器中的垃圾回收机制不是线程安全的
反向验证GIL的存在 如果不存在会产生垃圾回收机制与正常线程之间数据错乱
GIL是加在CPython解释器上面的互斥锁
同一个进程下的多个线程要想执行必须先抢GIL锁 所以同一个进程下多个线程肯定不能同时运行 即无法利用多核优势
所有的解释型语言都无法做到同一个进程下多个线程利用多核优势