zoukankan      html  css  js  c++  java
  • Python--进程与线程

    一,回顾操作系统的概念

     操作系统位于底层硬件与应用软件之间的一层

     工作方式:向下管理软件,向上提供接口

    二,进程线程的概念

      进程是一个资源单位,线程是一个最小的执行单位

        一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程

    三,并行与并发

    并行:
        就是有多个进程可以同时运行的叫做并行
    并发:
        就是在一个处理器的情况下,切换执行,叫做并发

    python无法实现并行处理,因为全局解释器锁gil导致同一时刻同一进程
    只能有一个线程被运行。

        GIL全局解释器锁
        但是不影响Python开多进程

    多线程代码示例
        

    import threading
    import time
    '''
    程序在运行是有一个主线程,当程序开启多线程的时候,主线程依旧会执行,
    主线程执行到最后时,并没有结束,而是在等待子线程的结束后主线程结束
    
    '''
    def misc():
        print("听歌")
        time.sleep(3)
        print("听歌结束")
    
    
    def xieboke():
        print("写博客")
        time.sleep(5)
        print("写博客结束")
    
    
    #开启线程
    t1=threading.Thread(target=misc)#t1,t2是一个线程对象
    t2=threading.Thread(target=xieboke)
    
    t1.start()
    t2.start()
    
    print("主线程")



    #开启多线程的另一种方式

    import threading
    import time
    class MyThread(threading.Thread):
        '''
        用类的继承,继承线程的方法开启线程
        '''
    
        def __init__(self,num):
        '''
        继承父类的__init__方法
        '''
            threading.Thread.__init__(self)
            self.num=num
    
        def run(self):
            print("running on mythread:%s"%self.num)
            time.sleep(3)
            print("end%s"%self.num)
    
    t1=MyThread(10)
    t2=MyThread(20)
    
    t1.start()
    t2.start()
    print("主线程")



    jion的使用
        t.jion方法会阻塞主进程的运行,但不会影响其他线程的运行

    setDaemon方法
        -守护线程
        当某个线程设置为守护线程的时候,它会随着主线程的结束而结束
        t.setDaemon(True)
        
    线程对象下的几个方法:
            -isAlive()检测线程是否活动,返回值是布尔值
            -getName():返回线程名
            -setName():设置线程名称
            
    threading模块提供的一些方法:
        threading.currentTread():返回当前线程变量
        threading.enumerate():返回一个包含正在运行的线程的list。
        threading.activeCount():返回正在运行的线程数量
        
    Python对于计算密集型运行比较慢,效率低;对于IO密集型效率有明显提高

    Python多线程
        互斥锁:
            互斥锁的意义就是在保护锁内代码同一时间只有一个线程在使用
            直到代码执行完成,解锁后其他线程才能执行所内代码。
        使用格式:
            -lock=threading.Lock()创建一把锁的对象
            lock.acquire()#加锁
            ....需要保护的执行语句
            lock.release()#解锁
        
        死锁与递归锁    
        代码示例:
          

           import threading
            import time
    
            muteA=threading.Lock()
            muteB=threading.Lock()
    
            class MyThread(threading.Thread):
                def __init__(self):
                    threading.Thread.__init__(self)
    
                def run(self):
                    self.func1()
                    self.func2()
    
                def func1(self):
                    muteA.acquire()
                    print("锁A执行内容",MyThread.getName(self))
                    muteB.acquire()
                    print("锁B执行内容",MyThread.getName(self))
                    muteB.release()
                    muteA.release()
    
                def func2(self):
                    muteB.acquire()
                    print("第二个函数的锁B",MyThread.getName(self))
                    muteA.acquire()
                    print("第二个函数的锁A",MyThread.getName(self))
                    muteA.release()
                    muteB.release()
    
            if __name__=="__main__":
                for i in range(10):
                    my_thread=MyThread()
                    my_thread.start()


            
        形成死锁的原因在于当线程1在第二个函数中拿到锁B向下执行需要锁A的时候,线程2在函数1中
        已经拿到的锁A,在等待线程1释放B。两个线程都没有释放另一个线程需要的锁,所以就形成了死锁。
        
        
        递归锁的应用
        递归锁未避免死锁的产生,在锁内实行一个引用计数,当有一把使用是计速器加一,释放后,去除计数
        到代码在执行锁内代码时,如果有其他线程抢锁,计数如果为零,线程可以拿到锁,大于零,拒绝线程拿锁
        这样就能避免锁的重复,也就不会产生死锁
        代码示例:    
        import threading
            import time

            Rlock=threading.Rlock()

            class MyThread(threading.Thread):
                def __init__(self):
                    threading.Thread.__init__(self)

                def run(self):
                    self.func1()
                    self.func2()

                def func1(self):
                    Rlock.acquire()
                    print("锁A执行内容",MyThread.getName(self))
                    Rlock.acquire()
                    print("锁B执行内容",MyThread.getName(self))
                    Rlock.release()
                    Rlock.release()

                def func2(self):
                    Rlock.acquire()
                    print("第二个函数的锁B",MyThread.getName(self))
                    Rlock.acquire()
                    print("第二个函数的锁A",MyThread.getName(self))
                    Rlock.release()
                    Rlock.release()

            if __name__=="__main__":
                for i in range(10):
                    my_thread=MyThread()
                    my_thread.start()
                    
    event方法使用:
        event方法可以让两个线程之间通信,当一个线程需要另一个线程准备数据的时候,
        event.wait(),阻塞程序的运行,直到另一个线程将数据准备完成后,使用event.set()
        返回一个true值,event.wait()接受到该值之后,线程开始运行。wait方法后可以接一个超时
        时间参数,规定在一定时间内阻塞,超时后运行。
        
        import threading
        import time
        import logging

        logging.basicConfig(level=logging.DEBUG, format='(%(threadName)-10s) %(message)s',)


        def worker(event):
            logging.debug('Waiting for redis ready...')

            while not event.isSet():
                logging.debug("wait.......")
                event.wait(3)   # if flag=False阻塞,等待flag=true继续执行


            logging.debug('redis ready, and connect to redis server and do some work [%s]', time.ctime())
            time.sleep(1)

        def main():

            readis_ready = threading.Event()  #  flag=False创建一个event对象
            t1 = threading.Thread(target=worker, args=(readis_ready,), name='t1')
            t1.start()

            t2 = threading.Thread(target=worker, args=(readis_ready,), name='t2')
            t2.start()

            logging.debug('first of all, check redis server, make sure it is OK, and then trigger the redis ready event')

            time.sleep(6) # simulate the check progress
            readis_ready.set()  # flag=Ture
            

        if __name__=="__main__":
            main()
        

    进程multprocessing模块

        multprocessing模块与threading模块使用同一套api,使用方法调用方法与threading模块一样
        
        代码示例:
        from multiprocessing import Process

        import time

        def f(name):
            print("hello",name,time.ctime())
            time.sleep(1)

        if __name__=="__main__":
            p_list=[]
            for i in range(3):
                p=Process(target=f,args=("alvin:%s"%i,))
                p_list.append(p)
                p.start()
        
        
    协程的应用:
        协程是单线程的,不能切换。因为协程对IO操作的判断由自己控制
        import time

        #  可以实现并发


        def consumer():

            r = ''
            while True:

                n = yield r
                if not n:
                    return
                print('[CONSUMER] ←← Consuming %s...' % n)
                time.sleep(1)
                r = '200 OK'

        def produce(c):

            next(c)
            n = 0
            while n < 5:
                n = n + 1
                print('[PRODUCER] →→ Producing %s...' % n)

                cr = c.send(n)

                print('[PRODUCER] Consumer return: %s' % cr)

            c.close()

        if __name__=='__main__':

            c = consumer()
            produce(c)
        
    gevent模块的使用:
        from gevent import monkey
        monkey.patch_all()

        import gevent
        from urllib import request
        import time

        def f(url):
            print('GET: %s' % url)
            resp = request.urlopen(url)
            data = resp.read()
            print('%d bytes received from %s.' % (len(data), url))

        start=time.time()

         gevent.joinall([
                 gevent.spawn(f, 'https://itk.org/'),
                 gevent.spawn(f, 'https://www.github.com/'),
                 gevent.spawn(f, 'https://zhihu.com/'),
         ])

        #f('https://itk.org/')
        #f('https://www.github.com/')
        #f('https://zhihu.com/')


        print(time.time()-start)  

  • 相关阅读:
    1641. 统计字典序元音字符串的数目
    1688. 比赛中的配对次数
    核心思路
    面试题 16.17. 连续数列
    70. 爬楼梯
    面试题 08.01. 三步问题
    剑指Offer 42. 连续子数组的最大和
    设计模式之原型模式
    代理模式之动态代理
    设计模式之禅(六大设计原则)
  • 原文地址:https://www.cnblogs.com/lzh1118/p/7430014.html
Copyright © 2011-2022 走看看