day38

(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解释器)
'''

 

posted @ 2020-08-25 21:07  板鸭没有腿  阅读(95)  评论(0)    收藏  举报