zoukankan      html  css  js  c++  java
  • Python36 1.joinablequeue 2.线程理论 3.多线程对比多进程 4.线程的使用方式 4.1.产生 线程的两种方式 4.2.守护线程 4.3.线程安全问题 4.3.1.互斥锁 4.3.2.死锁 4.3.3.可重入锁 4.3.4.信号量

    复习
    1.守护进程
    2.互斥锁(解决数据错乱的方法)
    3.IPC(进程间通讯)
    4.生产者与消费者模型

    详解:
    1.守护进程
    一个进程可以设为另一个进程的守护进程
    特点:被守护的进程结束时,守护进程也会随之结束
    本质:父进程交给子进程一个任务,然而父进程 先于子进程结束了,子进程的任务也就没有必要 继续执行了
    格式:开始前加 p.daemon=True

    2.互斥锁(解决数据错乱的方法)
    方法一:互斥锁
    互斥 互相排斥
    锁的本质:一个标志
    标志的两个状态:
    1.锁定
    2.未锁定
    什么时候用?
    当多个进程要操作同一个资源时,就会造成数据错乱,通常将1.写入操作加锁 2.读取操作不需加
    锁的作用:(优缺点)
    (缺点:)加锁会把原本并发的任务,修改为串行,降低了效率 (优点:)保证了数据的安全性,锁可以指定一部分代码串行,其他仍然并发
    重点考虑问题:加锁的位置
    注意:
    1.要保证安全必须保证大家用的是同一把锁
    2.不能对一把锁连续执行acquire,将会导致死锁
    方法二:
    join
    本质:
    1.join也可以将任务变为串行
    2.join固定任务的执行顺序
    3.join会使得子进程的代码全部串行,并且主进程也会阻塞住

    3.IPC
    进程间通讯:
    1.管道(subprocess)
    单向通讯,传输的是二进制
    2.共享文件(with open()as f)
    数据量几乎不受限制,但是速度慢
    3.共享内存(1.Manager2.Queue)
    数据量较小 但是速度快
    4. socket("服务器","客户端")
    编程复杂 ,传输的是二进制

    最主要的内容就是共享内存:
    1.Manager()类 了解
    2.Queue队列 (q=Queue()) 必须掌握的方法
    是一种数据容器,
    特点:先进先出,并且进程中的队列 可以共享数据,自带锁机制

    4.生产者消费者模型
    要解决的问题:生产者与消费者能力不平衡,导致效率低
    如何解决?
    1.把生产者和消费者分开耦合,即把任务分到不同进程中 各司其职
    2.分开后,由于进程间相互隔离,所以需要一个共享容器,Queue 闪亮登场
    (1.解决了数据交换问题2.锁的问题)


    今日内容
    1.joinablequeue
    2.线程理论
    3.多线程对比多进程
    4.线程的使用方式
    --1.产生 线程的两种方式
    --2.守护线程
    --3.线程安全问题
    ----1.互斥锁
    ----2.死锁
    ----3.可重入锁
    ----4.信号量


    今日内容详解
    1.joinablequeue队列
    join等待某个任务完成
    able 可以怎么着
    Queue 队列
    翻译:可以被join的队列

    #案列说明:(格式框架)
    '''
    from multiprocessing import JoinableQueue
    #1.创建队列 不指定maxsize则没有数量限制
    q=JoinableQueue()
    print("_______________________________________")
    #2.存储元素
    q.put("123")
    q.put("abc")
    #3.取出元素
    print("取走一个%s数据"%(q.get()))
    #4.q.task_done()告诉队列这个数据已经被处理完
    q.task_done()
    '''
    注意:q.task_done()该函数不是表示任务全部处理完成 而是取出来某个数据处理完成
    '''
    print("在取走了一个%s"%(q.get()))
    q.task_done()
    print(".......................................")
    #5.q.join()等待队列中的数据被处理完毕
    q.join()
    q.join()
    '''
    q.join()等待队列中的数据被处理完毕
    join task_done的次数==put的调用次数
    '''
    print("over!")
    '''

    _______________________________________
    取走一个123数据
    在取走了一个abc
    .......................................
    over!

    '''

    2.线程理论
    什么是线程?
    线程是操作系统最小的运算调度单位,被包含在进程中,一个线程就是一个固定的执行流程

    3.多线程对比多进程
    线程与进程关系: 重点
    1.线程不能单独存在,必须存在于进程中,
    进程是一个资源单位,其包含了运行程序所需的所有资源
    线程才是真正的执行单位。
    2.主线程:没有线程,进程中的资源无法被利用起来,所以每个进程至少包含一个线程,称之为主线程
    主线程的创建条件:
    当我们启动一个程序时,操作系统就会为自己创建一个主线程
    子线程:线程可以由程序后期开启,自己开启线程称为子线程

    为什么需要线程?
    目的:提高执行效率
    例如:一个车间如果产量跟不上就再造一条流水线
    当然也可以再造一个新车间,但需要把原材料运过去,过程是非常耗时的
    所以通常创建新的流水线,即线程,而非进程(车间)
    4.线程的使用方式
    使用方法和多进程一致,不过开启线程的代码可以放在任意位置,而开启进程必须放在判断下面
    --1.产生 线程的两种方式
    1.实例化Thread类,target参数用于指定子线程要执行的任务
    2.继承Thread类,覆盖run方法

    案例说明:
    from threading import Thread,current_thread
    import time

    def task():
    print("2",current_thread())
    print("子线程running")
    time.sleep(10)
    print("子线程over")

    # 1.使用方法一 直接实例化Thread类
    if __name__ == '__main__':
    t = Thread(target=task)
    t.start()

    # task()
    # 执行顺序不固定 如果开启线程速度足够快 可能子线程先执行
    print("主线程over")
    print("1",current_thread())
    #print(threading.current_thread().name) #获取当前线程对象
    # 2.使用方法二 继承Thread 覆盖run方法
    class MyThread(Thread):
    def run(self):
    print("子线程run!")
    m = MyThread()
    print("主线over")


    3. 线程的特点:重点:
    1.创建开销小
    案例说明:
    from threading import Thread
    from multiprocessing import Process
    import os,time
    def task():
    #print("haha")
    #print(os.getpid())
    pass
    if __name__=="__main__":
    st_time=time.time()
    ts=[]
    for i in range(100):
    #t = Process(target=task)
    t=Thread(target=task)
    t.start()
    ts.append(t)
    for t in ts:
    t.join()
    print(time.time()-st_time)
    #print("over")
    #线程值0.010971784591674805
    #进程值2.9180967807769775
    2.同一个进程之中线程数据共享:
    案例说明:
    from threading import Thread

    a=10
    def task():
    global a
    print("子running..")
    a=30
    t=Thread(target=task)
    t.start()
    t.join()# 主线程等待子线执行完毕
    print(a)
    '''
    值:
    子running..
    30
    '''
    3.多个线程之间是平等关系,没有父子关系。所有线程的PID都是相同的(处于同一进程,即同一车间)
    --2.守护线程 了解
    ​ 一个线程可以设置为另一个线程的守护线程
    ​ 特点: 被守护线程结束后守护线程也随之结束
    注:
    1.守护线程会等到所有非守护线程结束后结束 ! 前提是除了主线程之外 还有后别的非守护
    2.当然如果守护线程已经完成任务 立马就结束了
    3.如果守护线程先结束运行,被守护进程继续运行
    #案例说明
    #结束顺序:其他子线程,主线程,守护线程
    from threading import Thread
    import time
    def task():
    print("子1running......")
    time.sleep(100)
    print("子1over......")
    def task2():
    print("子2running......")
    time.sleep(4)
    print("子2over......")
    if __name__=="__main__":
    t = Thread(target=task)
    t.daemon = True
    t.start()
    t2 = Thread(target=task2)
    t2.start()
    print("主over")
    '''
    值:
    子1running......
    子2running......
    主over
    子2over......
    '''

    --3.线程安全问题
    ----1.互斥锁
    ​ 共享意味着竞争 (同一个进程之中线程数据共享)
    ​ 线程中也存在安全问题,
    ​ 多线程可以并发执行,一旦并发了并且访问了同一个资源就会有问题
    ​ 解决方案:还是互斥锁
    # 用于访问当前正在运行的所有线程#print(enumerate())
    案例说明:
    from threading import Thread,enumerate,Lock
    import time
    number = 10
    lock = Lock()
    def task():
    global number
    lock.acquire()
    a = number
    time.sleep(0.1)
    number = a - 1
    lock.release()
    if __name__=="__main__":
    for i in range(10):
    t = Thread(target=task)
    t.start()
    for t in enumerate()[1:]:
    print(t)
    '''

    <Thread(Thread-1, started 18800)>
    <Thread(Thread-2, started 20708)>
    <Thread(Thread-3, started 2292)>
    <Thread(Thread-4, started 18396)>
    <Thread(Thread-5, started 11320)>
    <Thread(Thread-6, started 19228)>
    <Thread(Thread-7, started 20600)>
    <Thread(Thread-8, started 20200)>
    <Thread(Thread-9, started 19472)>
    <Thread(Thread-10, started 24484)>
    '''
    t.join()
    #print(number)#值0
    # 用于访问当前正在运行的所有线程
    #print(enumerate())#值[<_MainThread(MainThread, started 22716)>]
    ----2.死锁问题
    什么是死锁?
    当程序出现了不止一把锁,分别被不同的线程持有, 有一个资源要想使用必须同时具备两把锁 这时候程序就会进程无限卡死状态 ,这就称之为死锁
    如何避免死锁问题
    锁不要有多个,一个足够
    如果真的发生了死锁问题,必须迫使一方先交出锁
    案例说明:
    from threading import Lock, Thread, current_thread
    #筷子
    import time
    lock1=Lock()
    #盘子
    lock2=Lock()

    def eat1():
    lock2.acquire()
    print("%s抢到了盘子" % current_thread().name)
    time.sleep(0.5)
    lock1.acquire()
    print("%s抢到了筷子" % current_thread().name)
    print("%s开吃了!" % current_thread().name)

    print("%s放下筷子" % current_thread().name)
    lock1.release()
    print("%s放下盘子" % current_thread().name)
    lock2.release()
    def eat2():
    lock1.acquire()
    print("%s抢到了筷子" % current_thread().name)
    lock2.acquire()
    print("%s抢到了盘子" % current_thread().name)
    print("%s开吃了!" % current_thread().name)
    print("%s放下盘子" % current_thread().name)
    lock2.release()
    print("%s放下筷子" % current_thread().name)
    lock1.release()
    if __name__=="__main__":
    t1 = Thread(target=eat1)
    t2 = Thread(target=eat2)
    t1.start()
    t2.start()
    '''
    值:Thread-1抢到了盘子 Thread-2抢到了筷子
    '''
    ----3.可重入锁 了解
    Rlock :
    称之为递归锁或者可重入锁
    Rlock不是用来解决死锁问题的
    与Lock唯一的区别:
    Rlock同一线程可以多次执行acquire 但是执行几次acquire就应该对应release几次
    案例说明:
    from threading import Lock, Thread, RLock
    l=RLock()
    #l=Lock()
    def task():
    l.acquire()
    print("1")
    l.acquire()
    print("2")
    l.release()
    l.release()
    if __name__=="__main__":
    t=Thread(target=task)
    t.start()
    #值1(用Lock问题)
    #值1 2(用Rlock)
    ----4.信号量
    samaphore锁住一个公共厕所,同时可以来一大堆人
    用途:
    仅用于控制并发访问 并不能防止并修改造成的问题
    案例说明:
    from threading import Semaphore, Thread
    import time
    s=Semaphore(2)#限制一次性允许几人访问
    def task():
    s.acquire()
    print("子run")
    time.sleep(3)
    print("子over")
    s.release()
    if __name__=="__main__":
    for i in range(3):
    t = Thread(target=task)
    t.start()
    '''
    值:子run 子run 子over 子over 子run 子over
    '''

    5.Thread类常用属性
    # threading模块包含的常用方法
    import threading
    print(threading.current_thread().name) #获取当前线程对象
    print(threading.active_count()) # 获取目前活跃的线程数量
    print(threading.enumerate()) # 获取所有线程对象

    t = Thread(name="aaa")
    # t.join() # 主线程等待子线程执行完毕
    print(t.name) # 线程名称
    print(t.is_alive()) # 是否存活
    print(t.isDaemon()) # 是否为守护线程


  • 相关阅读:
    【POJ1961】period
    主席树入门
    noip模拟【tea】
    noip模拟【service】
    noip模拟【noname】
    clearfix清除浮动
    九大内置对象
    2017/10/10 jar包错误
    mybatis案例源码详解
    自动类型转换
  • 原文地址:https://www.cnblogs.com/llx--20190411/p/10974050.html
Copyright © 2011-2022 走看看