zoukankan      html  css  js  c++  java
  • day36,多线程,线程中的锁机制,joinablequeue

                                                                                      多线程

    什么是线程 :是真正的执行单位

    线程不能单独存在 必须存在于进程中,

    进程是一个资源单位,其包含了运行程序所需的所有资源

    线程才是真正的执行单位

    没有线程,进程中的资源无法被利用起来,所以一个进程至少包含一个线程,称之为主线程

    当我们启动一个程序时,操作系统就会自己为这个程序创建一个主线程

    线程可以由程序后期开启 ,自己开启线程称之为子线程

    为什么需要线程:

    它的目的只有一个就是提高效率,

    因为在是在进程中,只有一个线程的话效率很低,多个线程就可以完成更多的工作,

    还有一个原因就是,在创建多个进程来完成的话,就会及其的消耗资源

    如何使用创建线程:

    两种方法

       一个使用Threading 类中的Thread 创建线程

       第二个方法是继承Thread这个类覆盖run方法创建线程,这个和进程的创建是差不多的

    实例:第一种方法

    from threading import Thread,current_thread
    import time
    
    def task():
        print("2",current_thread())
        print("子线程running")
        time.sleep(10)
        print("子线程over")
    
    # 使用方法一  直接实例化Thread类
    if __name__ == '__main__':
        t = Thread(target=task)
        t.start()
        
        # task()
        # 执行顺序不固定 如果开启线程速度足够快  可能子线程先执行
        print("主线程over")
        print("1",current_thread())

    实例:第二种方法

    # 使用方法二 继承Thread 覆盖run方法
    class MyThread(Thread):
        def run(self):
            print("子线程run!")
    m = MyThread()
    print("主线over")
    
    # 使用方法和多进程一模一样   开启线程的代码可以放在任何位置  开启进程必须放在判断下面

    线程的几个特点:
        1 开启线程不消耗资源,运行速度比叫进程要快

        2 在开启多个子线程后,线程之间的数据是共享的,所以就不存在什么进程中的queue和Manager 

        3 线程中是没有父子级的,都是相同的pid不存在谁要先执行,后执行的,都是通过自己抢占的,就算是有父子级,都是自己设置的

    守护线程:

    守护线程是和进程中的守护进程是一样的,就是被守护的线程如果死掉的话,那么守护线程也会随着死掉

    JoinAbleQueue

    这是一个相当一是Queue这样的一个列队,joinablequeue

      不同的是队列允许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。

    joinablequeue 中间需要注意的是在获取数据是需要使用 q.task_done()这个方法告诉进程,获取的每一个值,知道列队中的值被取完

    就算值取完了,列队也是会等待在添加值,然后在取,这样进程是不会结束的,所以就把这个进程设置为守护进程,通过被守护的进程结束

    那么,守护进程也会结束,看这样整个程序就结束了

    JoinAbleQueue 实例:
    from multiprocessing import Process,JoinableQueue
    import time,random
    def consumer(q):
        while True:
            time.sleep(random.randint(1,5))
            res=q.get()
            print('消费者拿到了 %s' %res)
            q.task_done()
    
    def producer(seq,q):
        for item in seq:
            time.sleep(random.randrange(1,2))
            q.put(item)
            print('生产者做好了 %s' %item)
        q.join()
    
    if __name__ == '__main__':
        q=JoinableQueue()
        seq=('包子%s' %i for i in range(10))
        p=Process(target=consumer,args=(q,))
        p.daemon=True #设置为守护进程,在主线程停止时p也停止,但是不用担心,producer内调用q.join保证了consumer已经处理完队列中的所有元素
        p.start()
    
        producer(seq,q)
    
        print('主线程')

    线程中的锁

    共享意味着竞争

    线程中也存在安全问题,

    多线程可以并发执行,一旦并发了并且访问了同一个资源就会有问题

    解决方案:还是互斥锁

    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()
    
    for i in range(10):
        t = Thread(target=task)
        t.start()
    
    for t in enumerate()[1:]:
        # print(t)
        t.join()
        
    print(number)
    View Code

    死锁:

    死锁就是在有多个锁的多个线程中,一个资源需要多重锁来锁住资源,那么有多个线程抢占这个资源,就会发生一个线程抢占一个锁,

    满足不了,这个资源需要双重锁,这样就会发生,死锁的问题,都不解不了锁,所以程序就只能等待下去

    可重入锁

    Rlock 同一个线程可以多次执行acquire,释放锁时,有几次acquire就要release几次。

    但是本质上同一个线程多次执行acquire时没有任何意义的,其他线程必须等到RLock全部release之后才能访问共享资源。

    所以Rlock仅仅是帮你解决了代码逻辑上的错误导致的死锁,并不能解决多个锁造成的死锁问题

    Rlock 的实例:

    # 同一把RLock 多次acquire
    #l1 = RLock()
    #l2 = l1
    
    # 不同的RLock 依然会锁死
    import threading
    from threading import Thread
    from multiprocessing import RLock
    
    l1 = RLock()
    l2 = RLock()
    
    def task():
        l1.acquire()
        print(threading.current_thread().name,"拿到了筷子")
        l2.acquire()
        print(threading.current_thread().name, "拿到了盘子")
    
        print("吃饭")
        l1.release()
        l2.release()
    
    def task2():
        l2.acquire()
        print(threading.current_thread().name, "拿到了盘子")
    
        l1.acquire()
        print(threading.current_thread().name,"拿到了筷子")
    
        print("吃饭")
    
        l2.release()
        l1.release()
    
    t1 = Thread(target=task)
    t1.start()
    t2 = Thread(target=task2)
    t2.start()
    View Code

     

    信号量:

    Semaphore

    信号量也是一种锁,其特殊之处在于可以让一个资源同时被多个线程共享,并控制最大的并发访问线程数量。

    Semaphore 是用于用户访问服务器的最大的并发量,可以限制访问的人数,一般不用于线程

    如果把Lock比喻为家用洗手间,同一时间只能一个人使用。

    那信号量就可以看做公共卫生间,同一时间可以有多个人同时使用。

    from threading import  Thread,Semaphore,current_thread
    import time
    
    s = Semaphore(3)
    def task():
        s.acquire()
        print("%s running........" % current_thread())
        time.sleep(1)
        s.release()
        
    for i in range(20):
        Thread(target=task).start()
  • 相关阅读:
    88. Merge Sorted Array
    87. Scramble String
    86. Partition List
    85. Maximal Rectangle
    84. Largest Rectangle in Histogram
    83. Remove Duplicates from Sorted List
    82. Remove Duplicates from Sorted List II
    81. Search in Rotated Sorted Array II
    80. Remove Duplicates from Sorted Array II
    计算几何——点线关系(叉积)poj2318
  • 原文地址:https://www.cnblogs.com/WBaiC1/p/10976042.html
Copyright © 2011-2022 走看看