生产者与消费者模式
在线程世界中,生产者即产生数据的线程,消费者即使用数据的线程,在使用多线程的时候,生产者和消费者处理数据的速度不一定一样,如果生产者处理数据的速度比消费者处理数据的速度快,那么生产者必须等消费者处理完数据才能继续生产,相反,如果生产者处理数据的速度比消费者处理数据的速度慢,那么消费者必须等待生产者。为了解决等待问题,引入了生产者消费者模式。
生产者和消费者之间通过一个队列来解决强耦合问题,生产者将数据添加到队列中,消费者从队列中使用数据,两者不直接通讯。这个队列是用来给生产者和消费者解耦的。
和进程不同的是,进程中使用队列用于进程间通信:from multiprocessing import Queue
线程中使用队列:from queue import queue(python3中);
from queue import queue(python2中)
不过,进程和线程中关于Queue的所有操作都是一样的,即put,get,qsize,full,empty等。
# encoding=utf-8
import threading
import time
#python2中
#from Queue import Queue
#python3中
from queue import Queue
class Producer(threading.Thread):
def run(self):
global queue
count = 0
while True:
if queue.qsize() < 1000:
for i in range(100):
count = count +1
msg = '生成产品'+str(count)
queue.put(msg)
print(msg)
time.sleep(0.5)
class Consumer(threading.Thread):
def run(self):
global queue
while True:
if queue.qsize() > 100:
for i in range(3):
msg = self.name + '消费了 '+queue.get()
print(msg)
time.sleep(1)
if __name__ == '__main__':
queue = Queue()
for i in range(500):
queue.put('初始产品'+str(i))
# 两个生产者
for i in range(2):
p = Producer()
p.start()
# 五个消费者
for i in range(5):
c = Consumer()
c.start()
threadLocal对象在线程中的使用
# coding=utf-8
import threading
# 创建全局ThreadLocal对象:
local_school = threading.local()
def process_student():
# 获取当前线程关联的student:
std = local_school.student
print('Hello, %s (in %s)' % (std, threading.current_thread().name))
def process_thread(name):
# 绑定ThreadLocal的student:
local_school.student = name
process_student()
t1 = threading.Thread(target= process_thread, args=('dongGe',), name='Thread-A')
t2 = threading.Thread(target= process_thread, args=('老王',), name='Thread-B')
t1.start()
t2.start()
异步
同步:你喊你朋友吃饭 ,你朋友在忙 ,你就⼀直在那等,等你
朋友忙完了 ,你们⼀起去。
异步:你喊你朋友吃饭,你朋友在忙,便告诉你:你先去忙,等我这边结束了去找你。
异步的好处是,当使用多进程时,主进程不需要一直等待子进程结束,可以先去做自己的事情,当子进程结束的时候操作系统会告诉主进程,子进程已结束,然后主进程会停下手中的任务转而去做操作系统安排的任务。
# coding=utf-8
from multiprocessing import Pool
import time
import os
def test():
print("---进程池中的进程---pid=%d,ppid=%d--"%(os.getpid(),os.getppid()))
for i in range(3):
print("----%d---"%i)
time.sleep(1)
return "hahah"
def test2(args):
print("---callback func--pid=%d"%os.getpid())
print("---callback func--args=%s"%args)
if __name__=="__main__":
pool = Pool(3)
pool.apply_async(func=test,callback=test2)
#异步的理解:主进程正在做某件事情,突然 来了一件更需要立刻去做的事情,
#那么这种,在父进程去做某件事情的时候 并不知道是什么时候去做,的模式 就称为异步
while True:
time.sleep(1)
print("----主进程-pid=%d----"%os.getpid())
# ---进程池中的进程---pid=14912,ppid=14776--
# ----0---
# ----主进程-pid=14776----
# ----1---
# ----主进程-pid=14776----
# ----2---
# ----主进程-pid=14776----
# ---callback func--pid=14776
# ---callback func--args=hahah
# ----主进程-pid=14776----
# ----主进程-pid=14776----
# ----主进程-pid=14776----
# ----主进程-pid=14776----
GIL
GIL,全局解释器锁,作用是限制多线程同时执行,保证同一时间内只有一个线程在执行。那为什么要这么做呢?因为对于多线程而言,全局变量是共享的,为了线程的安全,需要保证同一时刻只有一个线程在工作,因此在单核或多核处理器中,多线程并不能并行,只是并发而已,不能提高效率,反而多线程执行一个程序所用时间可能比单线程还要多,因为操作系统不断调度各个线程浪费了时间。
那我们说的多线程提高效率指的是什么?多线程提高效率,不如说是提高了CPU的执行时间,即减少了等待时间。
并发,指的是一个处理器同时处理多个任务,并行指的是多个处理器同时处理多个任务,就好比一个人同时吃三个馒头和三个人吃三个馒头,并发的时间肯定是并行的三倍。
那么解决多线程效率的方案有哪些?
- 在需要并行的地方用C语言写
- 能用进程就不用线程
- 将cpython解释器换jpython,因为 GIL只有cpython解释器。