(1)生产者消费者模型以及joinablequeue
(2)线程理论及线程的开启方式
(3)线程之间数据共享
(4)线程对象的使用方法
(5)守护线程
(6)线程互斥锁
# 生产者消费者模型
'''
# (1)
from multiprocessing import Process, Queue
import time
import random
def producer(q, name, thing):
for i in range(10):
q.put(thing)
print(f'{name} 生产了 {thing}')
time.sleep(random.randint(1, 2))
def consumer(q, name):
while True:
thing = q.get()
if thing == None:
return
print(f'{name} 消费了 {thing}')
time.sleep(random.randint(1, 2))
if __name__ == '__main__':
q = Queue()
p1 = Process(target=producer, args=(q, 'producerA', 'PC'))
p2 = Process(target=producer, args=(q, 'producerB', 'SP'))
c1 = Process(target=consumer, args=(q, 'consumerA'))
c2 = Process(target=consumer, args=(q, 'consumerB'))
c3 = Process(target=consumer, args=(q, 'consumerC'))
p1.start()
p2.start()
c1.start()
c2.start()
c3.start()
p1.join()
p2.join()
q.put(None)
q.put(None)
q.put(None)
# (2)
# JoinableQueue除了与Queue相同的方法之外,还具有以下方法:
# q.task_done():使用者使用此方法发出信号,表示q.get()返回的项目已经被处理。如果调用此方法的次数大于从队列中删除的项目数量,将引发ValueError异常。
# q.join():生产者将使用此方法进行阻塞,直到队列中所有项目均被处理。阻塞将持续到为队列中的每个项目均调用q.task_done()方法为止。
from multiprocessing import Process, JoinableQueue
import time
import random
def producer(q, name, thing):
for i in range(10):
q.put(thing)
print(f'{name} 生产了 {thing}')
time.sleep(random.randint(1, 2)) # 时间模拟
def consumer(q, name):
while True:
thing = q.get()
print(f'{name} 消费了 {thing}')
time.sleep(random.randint(1, 2)) # 时间模拟
q.task_done() # 计数减一
if __name__ == '__main__':
q = JoinableQueue()
p1 = Process(target=producer, args=(q, 'producerA', 'PC'))
p2 = Process(target=producer, args=(q, 'producerB', 'SP'))
c1 = Process(target=consumer, args=(q, 'consumerA'))
c2 = Process(target=consumer, args=(q, 'consumerB'))
c3 = Process(target=consumer, args=(q, 'consumerC'))
p1.start()
p2.start()
c1.daemon = True # 由于消费者进程中存在while死循环,所以必须设为守护进程,否则消费者子进程会一直运行
c2.daemon = True
c3.daemon = True
c1.start()
c2.start()
c3.start()
p1.join()
p2.join()
q.join() # 阻塞程序,直到队列中的数据处理完毕
print('end.........')
'''
# 开启线程的方式
'''
# 进程是资源分配的最小单位,线程是CPU调度的最小单位,每个进程中至少有一个线程
# (1)
# from threading import Thread
# import time
#
#
# def task():
# print('begin...')
# time.sleep(2)
# print('end...')
#
#
# if __name__ == '__main__':
# t = Thread(target=task)
# t.start()
# print('main.....')
# (2)
# from threading import Thread
# import time
#
# class MyThread(Thread):
# def run(self) -> None:
# print('begin...')
# time.sleep(2)
# print('end...')
#
#
# if __name__ == '__main__':
# t = MyThread()
# t.start()
# print('main.....')
'''
# 线程之间数据共享
'''
from threading import Thread
a = 10
def task(a_new):
global a
print('begin...')
a = a_new
print('end...')
if __name__ == '__main__':
t1 = Thread(target=task,args=(22,))
t1.start()
t2 = Thread(target=task,args=(33,))
t2.start()
print('main.....')
print(a)
'''
# 线程对象的方法
'''
# join() 主线程等待子线程运行结束
# from threading import Thread
# import time
#
#
# def task(n, id_name):
# print('开始 %s' % id_name)
# time.sleep(n)
# print('结束 %s' % id_name)
#
#
# if __name__ == '__main__':
# t1 = Thread(target=task, args=(2, '线程1'))
# t1.start()
# t2 = Thread(target=task, args=(3, '线程2'))
# t2.start()
# t1.join() # 等待子进程执行结束
# t2.join()
# print('主')
# from threading import Thread, current_thread, active_count
# import time
# import os
#
#
# def task(n, id_name):
# print('开始 %s' % id_name)
# print(id_name, current_thread().ident) # current_thread()当前线程对象,ident-->线程没有ID号,ident可当作线程ID
# print('线程名:', current_thread().name) # name 获取线程名(也可用getName()),默认从Thread-1开始依次往后排序,可在实例化时自定义name
# print(os.getpid()) # 当前进程的PID,同一个进程下的所有线程打印结果都相同
# time.sleep(n)
# print('结束 %s' % id_name)
#
#
# if __name__ == '__main__':
# t1 = Thread(target=task, args=(2, '线程1'), name='starfall')
# t1.start()
# t2 = Thread(target=task, args=(3, '线程2'))
# t2.start()
# print('当前活跃线程:', active_count()) # 获取当前活跃线程数量(主线程也会计入)
# print(t1.is_alive()) # 判断当前线程是否存活
# t1.join()
# t2.join()
# print(t2.is_alive())
# print('主')
'''
# 守护线程
'''
from threading import Thread
import time
def task(n, id_name):
print('开始 %s' % id_name)
time.sleep(n)
print('结束 %s' % id_name)
if __name__ == '__main__':
t1 = Thread(target=task, args=(3, '线程1'))
# t1.daemon = True
t1.setDaemon(True)
t1.start()
t2 = Thread(target=task, args=(1, '线程2'))
t2.start()
print('主')
# 主线程运行结束之后不会立刻结束,会等待所有其他非守护线程结束才会真正结束,因为主线程的结束意味着所在的进程的结束
'''
# 线程互斥锁
'''
from threading import Thread, Lock
money = 77
def task(mutex):
global money
mutex.acquire() # 修改数据前加锁
money -= 1
mutex.release() # 操作完成后释放,其他线程才能继续获取锁
if __name__ == '__main__':
l = []
mutex = Lock()
for i in range(10):
t = Thread(target=task, args=(mutex,))
l.append(t)
for t in l:
t.start()
print(money)
'''
# GIL全局解释器锁理论
'''
# 1 python的解释器有很多,cpython,jpython,pypy(python写的解释器)
# 2 python的库多,库都是基于cpython写起来的,其他解释器没有那么多的库
# 3 cpython中有一个全局大锁,每条线程要执行,必须获取到这个锁
# 4 为什么会有这个锁呢?python的垃圾回收机制
# 5 python的多线程其实就是单线程
# 6 某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行
# 7 总结:cpython解释器中有一个全局锁(GIL),线程必须获取到GIL才能执行,我们开的多线程,不管有几个cpu,同一时刻,只有一个线程在执行(python的多线程,不能利用多核优势)
# 8 如果是io密集型操作:开多线程
# 9 如果是计算密集型:开多进程
# ((8)和(9)只针对于cpython解释器)
'''