小渣渣学习笔记 python day35【线程 进程 锁 生产者消费者总结 池 】

#【记住】
#队列的特点和实现原理
    #特点:
        #1、进程之间的通信
        #2、数据安全
        #3、先进先出
    #实现原理
        #基于管道+锁
        #管道 基于文件级别的socket+pickle实现
#生产者消费者模型如何实现?
    #使用场景:
        #采集图片,爬取音乐,为了提高效率,抓取网页的过程是生产者,分析网页形成数据的的过程是消费者
        #监控系统,监控程序作为生产者,发送监控邮件报警,是消费者
        #生产者把邮件信息交给消息中间件redis,消费者从中间件中取值,然后发送邮件
    #框架:celery:可以做定时任务
#进程在计算机中扮演的角色
    #资源分配的最小单位,线程是操作系统调度的最小单位
    #进程之间内存隔离
    #多个进程之间是竞争的关系
    #进程三状态之间的转换,尽量减少io操作,可以用argv操作,避免 input
    #让我们程序运行过程中尽可能多的使用cpu资源
#为什么线程之间数据不安全
    #首先线程之间数据共享,共享主进程中的资源
    #如果线程中有赋值操作,操作代码在底层不是由一条完整的cpu指令完成,dis可以查看python代码底层指令
    #如果是if判断等语句,底层也不是由一条完整指令完成,这中间发生了GIL锁的切换(时间片轮转),可能导致数据不安全
    # import dis
    # def func(a):
    #     if a>0:
    #         print(a)
    #     else :print(0)
    # print(dis.dis(func))
#死锁
    #发生在多个线程,多个锁(资源需求)之间
    #当A,B线程都需要a和b资源,某一时间,A拿到了a,B拿到了b,2个线程就一直等待下去
    #锁有叠加
#queue是线程安全的 还有logging

#数据n共享,但是不安全,出现了 -=  += ,最终输出啥的都有
from threading import Thread,Lock
n = 0
def func1(lock):
    global n
    for i in range(100000):
        n += 1
def func2(lock):
    global n
    for i in range(100000):
        n -= 1
if __name__ == '__main__':
    t1 = Thread(target=func1)
    t2 = Thread(target=func2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(n)
#加锁,输出为0
from threading import Thread,Lock
n = 0
def func1(lock):
    global n
    with lock:
        for i in range(100000):
            n += 1
def func2(lock):
    global n
    with lock:
        for i in range(100000):
            n -= 1
if __name__ == '__main__':
    lock = Lock()
    t1 = Thread(target=func1,args=(lock,))
    t2 = Thread(target=func2,args=(lock,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(n)
#判断numbers最终长度是否一定为1,好像是的
import time
import threading
loop = int(1E5)
def _add(loop:int = 1):
    global numbers
    for _ in range(loop):
        numbers.append(0)

def _sub(loop:int = 1):
    global numbers
    for _ in range(loop):
        while not numbers:
            time.sleep(1E-6)
        numbers.pop()

numbers=[0]
t1 = threading.Thread(target=_add,args=(loop,))
t2 = threading.Thread(target=_sub,args=(loop,))
t1.start()
t1.join()
t2.start()

t2.join()

print(len(numbers))
#池
#为什么要用池?
    #如果先开好进程或者线程,那么有任务之后就可以直接使用这个池中的数据了
    #并且开好的线程或者进程会一直存在池中,可以被多个任务反复利用
    #极大的减少了开启,关闭,调度线程 和 进程的时间开销
    #池中的进程或者线程个数控制了操作系统需要调度的任务个数,控制池中的单位
    #有利于提高操作系统的效率,减轻操作系统的负担

#模块 concurrent.futures,平时启动进程池的机会不多,一般启动线程池
import time
import random
from threading import current_thread
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
def func():
    print(f'{current_thread().ident} start')
    time.sleep(random.randint(1,3))
    print(f'{current_thread().ident} end')
tp = ThreadPoolExecutor(5) #cpu + 1 个线程的线程池
for i in range(10):
    tp.submit(func)
#线程池里只有5个线程在运行,线程与线程之间不影响,一个结束,就马上处理下一个任务
上一篇:python学习day35笔记


下一篇:Day35 HTML基础、表单表格