zoukankan      html  css  js  c++  java
  • Python之旅.第九章.并发编程

    一、上节课复习

    1 守护进程:如果父进程将子进程设置为守护进程,那么在主进程代码运行完毕后守护进程就立即被回收

    2 互斥锁:用来将并发编程串行,牺牲了效率而保证了数据安全

    3 队列:管道+

     

    二、守护进程例子

    解决:消费者取空列表后q.get()阻塞的问题

    方法一:

    from multiprocessing import Process

     

    import time

    def foo():

        print(123)

        time.sleep(1)

        print("end123")

     

    def bar():

        print(456)

        time.sleep(3)

        print("end456")

     

    if __name__ == '__main__':

        p1=Process(target=foo)

        p2=Process(target=bar)

        p1.daemon=True        #主进程代码运行完毕,守护进程就会结束

        p1.start()

        p2.start()

    print("main-------")

     

    三、守护进程与应用

     

    import time

    import random

    from multiprocessing import Process,Queue

     

    def consumer(name,q):

        while True:

            res=q.get()

            if res is None:break

            time.sleep(random.randint(1,3))

            print('33[46m消费者===%s 吃了 %s33[0m' %(name,res))

     

    def producer(name,q,food):

        for i in range(5):

            time.sleep(random.randint(1,2))

            res='%s%s' %(food,i)

            q.put(res)

            print('33[45m生产者者===%s 生产了 %s33[0m' %(name,res))

     

    if __name__ == '__main__':

        #1、共享的盆

        q=Queue()

     

        #2、生产者们

        p1=Process(target=producer,args=('egon',q,'包子'))

        p2=Process(target=producer,args=('刘清政',q,'泔水'))

        p3=Process(target=producer,args=('杨军',q,'米饭'))

     

        #3、消费者们

        c1=Process(target=consumer,args=('alex',q))

        c2=Process(target=consumer,args=('梁书东',q))

     

     

        p1.start()

        p2.start()

        p3.start()

        c1.start()

        c2.start()

     

     

        # 在生产者生产完毕后,往队列的末尾添加一个结束信号None

        p1.join()

        p2.join()

        p3.join()

        # 有几个消费者就应该放几个结束信号

        q.put(None)

    q.put(None)   

     

    方法二:

    import time

    import random

    from multiprocessing import Process,JoinableQueue

     

    def consumer(name,q):

        while True:

            res=q.get()

            time.sleep(random.randint(1,3))

            print('33[46m消费者===%s 吃了 %s33[0m' %(name,res))

            q.task_done()

     

    def producer(name,q,food):

        for i in range(5):

            time.sleep(random.randint(1,2))

            res='%s%s' %(food,i)

            q.put(res)

            print('33[45m生产者者===%s 生产了 %s33[0m' %(name,res))

     

    if __name__ == '__main__':

        #1、共享的盆

        q=JoinableQueue()

     

        #2、生产者们

        p1=Process(target=producer,args=('egon',q,'包子'))

        p2=Process(target=producer,args=('刘清政',q,'泔水'))

        p3=Process(target=producer,args=('杨军',q,'米饭'))

     

        #3、消费者们

        c1=Process(target=consumer,args=('alex',q))

        c2=Process(target=consumer,args=('梁书东',q))

        c1.daemon=True   # c1.daemon=True 必须在c1.start()

        c2.daemon=True

     

        p1.start()

        p2.start()

        p3.start()

        c1.start()

        c2.start()

     

        # 确定生产者确确实实已经生产完毕

        p1.join()

        p2.join()

        p3.join()

        # 在生产者生产完毕后,拿到队列中元素的总个数,然后直到元素总数变为0q.join()这一行代码才算运行完毕

        q.join()

        #q.join()一旦结束意味着队列确实被取空,消费者已经确确实实把数据都取干净了

    print('主进程结束') 

     

    四、线程理论

    1、什么是线程

       线程指的是一条流水线的工作过程

       进程不是执行单位,是资源单位

       一个进程内自带一个线程,线程是执行单位

     

    2、进程VS线程

        1、同一进程内的线程们共享该进程内资源,不同进程内的线程资源肯定是隔离的

    2、创建线程的开销比创建进程要小的多

     

    4 线程中没有父子关系。相较于子线程、主线程特殊之处在于其代变了主进程的生命周期。

     

    主进程等待子进程结束然后结束,是为子进程回收资源。

    主线程等待子线程结束然后结束,是等待这个进程的代码(其他非守护线程)执行完毕。

     

    主进程:执行完代码就结束。

    主线程:所以子线程结束才结束。

     

    五、开启线程的两种方式

    方式一:导入Thread模块

    from threading import Thread

    import time

     

    def task(name):

        print('%s is running' %name)

        time.sleep(3)

     

    if __name__ == '__main__':

        t=Thread(target=task,args=('egon',))

        t.start()

    print('主线程')

     

    方式二:创建类继承Thread

    from threading import Thread

    import time

     

    class MyThread(Thread):

        def run(self):

            print('%s is running' %self.name)

            time.sleep(3)

     

    if __name__ == '__main__':

        t=MyThread()

        t.start()

    print('主线程')

     

    六、进程vs线程

    1、瞅一瞅PID Process ID

    from threading import Thread

    import time,os

     

    def task():

        print('%s is running' %os.getpid())

        time.sleep(3)

     

    if __name__ == '__main__':

        t=Thread(target=task,)

        t.start()

        print('主线程',os.getpid()) #一个进程中的子线程pid相同

     

    2、线程创建开销小

     

    3、同一进程内的多个线程共享该进程内的资源

    from threading import Thread

    import time,os

     

    x=1000

    def task():

        global x

        x=0

     

    if __name__ == '__main__':

        t=Thread(target=task,)

        t.start()

        t.join()

        print('主线程',x)   #主线程 0

     

    七、线程对象的其他方法

    from threading import Thread,current_thread,active_count,enumerate

    import time,os

     

    def task():

        print('%s is running' %current_thread().name)  #Thread-1 is running

        time.sleep(3)

     

    if __name__ == '__main__':

        t1=Thread(target=task,name='第一个线程')

        t2=Thread(target=task,)

        t3=Thread(target=task,)

        t1.start()

        t2.start()

        t3.start()

        print(t1.is_alive())  #True

        print(active_count()) #4

        print(enumerate())    #[<_MainThread(MainThread, started 4320768832)>, <Thread(第一个线程, started 123145551912960)>, <Thread(Thread-1, started 123145557168128)>, <Thread(Thread-2, started 123145562423296)>]  #当前活跃的线程

    print('主线程',current_thread().name)  #主线程 MainThread

     

    八、守护线程

    from threading import Thread,current_thread

    import time

     

    def task():

        print('%s is running' %current_thread().name)

        time.sleep(3)

     

    if __name__ == '__main__':

        t1=Thread(target=task,name='第一个线程')

        t1.daemon = True

        t1.start()

     

    print('主线程')

     

    from threading import Thread

    import time

    def foo():

        print(123)

        time.sleep(5)

        print("end123")

     

    def bar():

        print(456)

        time.sleep(3)

        print("end456")

     

    if __name__ == '__main__':

     

        t1=Thread(target=foo)

        t2=Thread(target=bar)

     

        t1.daemon=True

        t1.start()

        t2.start()

        print("main-------")

     

        '''

        123

        456

        main-------

        end456

    '''

     

    主进程:执行完代码就结束。

    主线程:所以子线程结束才结束。

    总结:只要进程内没有可执行的代码守护就结束

     

    九、线程互斥锁

    from threading import Thread,Lock

    import time

     

    mutex=Lock()

    x=100

     

    def task():

        global x

        mutex.acquire()

        temp=x

        time.sleep(0.1)

        x=temp-1

        mutex.release()

     

    if __name__ == '__main__':

        start=time.time()

        t_l=[]

        for i in range(100):

            t=Thread(target=task)

            t_l.append(t)

            t.start()

        for t in t_l:

            t.join()

     

        print('',x)    #0

    print(time.time()-start)

     

    十、死锁现象与递归锁

    from threading import Thread,Lock,RLock

    import time

     

    # mutexA=Lock()  #如果用Lock(互斥锁),会发生死锁现象

    # mutexB=Lock()

     

    mutexA=mutexB=RLock()  #是一把锁,可连续acqruie,但只有其上的计数为0时其他线程才可对其调用

     

    class MyThread(Thread):

        def run(self):

            self.f1()

            self.f2()

     

        def f1(self):

            mutexA.acquire()

            print('%s 拿到了A' %self.name)

     

            mutexB.acquire()

            print('%s 拿到了B' %self.name)

            mutexB.release()

     

            mutexA.release()

     

        def f2(self):

            mutexB.acquire()

            print('%s 拿到了B' %self.name)

            time.sleep(0.1)

     

            mutexA.acquire()

            print('%s 拿到了A' %self.name)

            mutexA.release()

     

            mutexB.release()

     

     

    if __name__ == '__main__':

        for i in range(10):

            t=MyThread()

            t.start()

     

    print('')

     

    十一、信号量

    # from multiprocessing import Semaphore #进程和线程中皆可导入Semaphore模块

    from threading import Thread,Semaphore,current_thread

    import time,random

     

    sm=Semaphore(5)  #5把钥匙,即同时可以5个对象进行执行

     

    def go_wc():

        sm.acquire()

        print('%s 上厕所ing' %current_thread().getName())

        time.sleep(random.randint(1,3))

        sm.release()

     

    if __name__ == '__main__':

        for i in range(23):

            t=Thread(target=go_wc)

            t.start()

  • 相关阅读:
    原则之读书笔记(生活篇)
    为 Nginx 添加 HTTP 基本认证(HTTP Basic Authentication)
    Linux搜索所有文件中的内容
    Js实现Table动态添加一行的小例子
    Android必学之数据适配器BaseAdapter
    技术共享之常见的6中种方法检测手机是否是虚拟机
    修改MySql数据库的默认时
    space.php
    self.location.href
    宝塔搭建laravel所需要的lnmp环境linux-nginx-mysql-php-composer-git
  • 原文地址:https://www.cnblogs.com/yangli0504/p/8955102.html
Copyright © 2011-2022 走看看