精华内容
下载资源
问答
  • python多线程详解(超详细)

    万次阅读 多人点赞 2019-09-28 08:33:31
    python中的多线程是一个非常重要的知识点,今天为大家对多线程进行详细的说明,代码中的注释有多线程的知识点还有测试用的实例。 import threading from threading import Lock... python多线程详解 什么是线程? ...

    python中的多线程是一个非常重要的知识点,今天为大家对多线程进行详细的说明,代码中的注释有多线程的知识点还有测试用的实例。
    码字不易,阅读或复制完了,点个赞!

    import threading
    from threading import Lock,Thread
    import time,os
    
    
    '''
                                          python多线程详解
          什么是线程?
          线程也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际运作单位。
          线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所
          拥有的全部资源。一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行
    '''
    
    '''
        为什么要使用多线程?
        线程在程序中是独立的、并发的执行流。与分隔的进程相比,进程中线程之间的隔离程度要小,它们共享内存、文件句柄
        和其他进程应有的状态。
        因为线程的划分尺度小于进程,使得多线程程序的并发性高。进程在执行过程之中拥有独立的内存单元,而多个线程共享
        内存,从而极大的提升了程序的运行效率。
        线程比进程具有更高的性能,这是由于同一个进程中的线程都有共性,多个线程共享一个进程的虚拟空间。线程的共享环境
        包括进程代码段、进程的共有数据等,利用这些共享的数据,线程之间很容易实现通信。
        操作系统在创建进程时,必须为改进程分配独立的内存空间,并分配大量的相关资源,但创建线程则简单得多。因此,使用多线程
        来实现并发比使用多进程的性能高得要多。
    '''
    
    '''
        总结起来,使用多线程编程具有如下几个优点:
        进程之间不能共享内存,但线程之间共享内存非常容易。
        操作系统在创建进程时,需要为该进程重新分配系统资源,但创建线程的代价则小得多。因此使用多线程来实现多任务并发执行比使用多进程的效率高
        python语言内置了多线程功能支持,而不是单纯地作为底层操作系统的调度方式,从而简化了python的多线程编程。
    '''
    
    
    '''
        普通创建方式
    '''
    # def run(n):
    #     print('task',n)
    #     time.sleep(1)
    #     print('2s')
    #     time.sleep(1)
    #     print('1s')
    #     time.sleep(1)
    #     print('0s')
    #     time.sleep(1)
    #
    # if __name__ == '__main__':
    #     t1 = threading.Thread(target=run,args=('t1',))     # target是要执行的函数名(不是函数),args是函数对应的参数,以元组的形式存在
    #     t2 = threading.Thread(target=run,args=('t2',))
    #     t1.start()
    #     t2.start()
    
    
    '''
        自定义线程:继承threading.Thread来定义线程类,其本质是重构Thread类中的run方法
    '''
    # class MyThread(threading.Thread):
    #     def __init__(self,n):
    #         super(MyThread,self).__init__()   #重构run函数必须写
    #         self.n = n
    #
    #     def run(self):
    #         print('task',self.n)
    #         time.sleep(1)
    #         print('2s')
    #         time.sleep(1)
    #         print('1s')
    #         time.sleep(1)
    #         print('0s')
    #         time.sleep(1)
    #
    # if __name__ == '__main__':
    #     t1 = MyThread('t1')
    #     t2 = MyThread('t2')
    #     t1.start()
    #     t2.start()
    
    
    '''
        守护线程
        下面这个例子,这里使用setDaemon(True)把所有的子线程都变成了主线程的守护线程,
        因此当主线程结束后,子线程也会随之结束,所以当主线程结束后,整个程序就退出了。
        所谓’线程守护’,就是主线程不管该线程的执行情况,只要是其他子线程结束且主线程执行完毕,主线程都会关闭。也就是说:主线程不等待该守护线程的执行完再去关闭。
    '''
    # def run(n):
    #     print('task',n)
    #     time.sleep(1)
    #     print('3s')
    #     time.sleep(1)
    #     print('2s')
    #     time.sleep(1)
    #     print('1s')
    #
    # if __name__ == '__main__':
    #     t=threading.Thread(target=run,args=('t1',))
    #     t.setDaemon(True)
    #     t.start()
    #     print('end')
    '''
        通过执行结果可以看出,设置守护线程之后,当主线程结束时,子线程也将立即结束,不再执行
    '''
    
    '''
        主线程等待子线程结束
        为了让守护线程执行结束之后,主线程再结束,我们可以使用join方法,让主线程等待子线程执行
    '''
    # def run(n):
    #     print('task',n)
    #     time.sleep(2)
    #     print('5s')
    #     time.sleep(2)
    #     print('3s')
    #     time.sleep(2)
    #     print('1s')
    # if __name__ == '__main__':
    #     t=threading.Thread(target=run,args=('t1',))
    #     t.setDaemon(True)    #把子线程设置为守护线程,必须在start()之前设置
    #     t.start()
    #     t.join()     #设置主线程等待子线程结束
    #     print('end')
    
    
    '''
        多线程共享全局变量
        线程时进程的执行单元,进程时系统分配资源的最小执行单位,所以在同一个进程中的多线程是共享资源的
    '''
    # g_num = 100
    # def work1():
    #     global  g_num
    #     for i in range(3):
    #         g_num+=1
    #     print('in work1 g_num is : %d' % g_num)
    #
    # def work2():
    #     global g_num
    #     print('in work2 g_num is : %d' % g_num)
    #
    # if __name__ == '__main__':
    #     t1 = threading.Thread(target=work1)
    #     t1.start()
    #     time.sleep(1)
    #     t2=threading.Thread(target=work2)
    #     t2.start()
    
    
    '''
            由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,
        所以出现了线程锁,即同一时刻允许一个线程执行操作。线程锁用于锁定资源,可以定义多个锁,像下面的代码,当需要独占
        某一个资源时,任何一个锁都可以锁定这个资源,就好比你用不同的锁都可以把这个相同的门锁住一样。
            由于线程之间是进行随机调度的,如果有多个线程同时操作一个对象,如果没有很好地保护该对象,会造成程序结果的不可预期,
        我们因此也称为“线程不安全”。
            为了防止上面情况的发生,就出现了互斥锁(Lock)
    '''
    # def work():
    #     global n
    #     lock.acquire()
    #     temp = n
    #     time.sleep(0.1)
    #     n = temp-1
    #     lock.release()
    #
    #
    # if __name__ == '__main__':
    #     lock = Lock()
    #     n = 100
    #     l = []
    #     for i in range(100):
    #         p = Thread(target=work)
    #         l.append(p)
    #         p.start()
    #     for p in l:
    #         p.join()
    
    
    '''
        递归锁:RLcok类的用法和Lock类一模一样,但它支持嵌套,在多个锁没有释放的时候一般会使用RLock类
    '''
    # def func(lock):
    #     global gl_num
    #     lock.acquire()
    #     gl_num += 1
    #     time.sleep(1)
    #     print(gl_num)
    #     lock.release()
    #
    #
    # if __name__ == '__main__':
    #     gl_num = 0
    #     lock = threading.RLock()
    #     for i in range(10):
    #         t = threading.Thread(target=func,args=(lock,))
    #         t.start()
    
    
    '''
        信号量(BoundedSemaphore类)
        互斥锁同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据,比如厕所有3个坑,
        那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去
    '''
    # def run(n,semaphore):
    #     semaphore.acquire()   #加锁
    #     time.sleep(3)
    #     print('run the thread:%s\n' % n)
    #     semaphore.release()    #释放
    #
    #
    # if __name__== '__main__':
    #     num=0
    #     semaphore = threading.BoundedSemaphore(5)   #最多允许5个线程同时运行
    #     for i in range(22):
    #         t = threading.Thread(target=run,args=('t-%s' % i,semaphore))
    #         t.start()
    #     while threading.active_count() !=1:
    #         pass
    #     else:
    #         print('----------all threads done-----------')
    
    '''
        python线程的事件用于主线程控制其他线程的执行,事件是一个简单的线程同步对象,其主要提供以下的几个方法:
            clear将flag设置为 False
            set将flag设置为 True
            is_set判断是否设置了flag
            wait会一直监听flag,如果没有检测到flag就一直处于阻塞状态
        事件处理的机制:全局定义了一个Flag,当Flag的值为False,那么event.wait()就会阻塞,当flag值为True,
        那么event.wait()便不再阻塞
    '''
    event = threading.Event()
    def lighter():
        count = 0
        event.set()         #初始者为绿灯
        while True:
            if 5 < count <=10:
                event.clear()  #红灯,清除标志位
                print("\33[41;lmred light is on...\033[0m]")
            elif count > 10:
                event.set()    #绿灯,设置标志位
                count = 0
            else:
                print('\33[42;lmgreen light is on...\033[0m')
    
            time.sleep(1)
            count += 1
    
    
    def car(name):
        while True:
            if event.is_set():     #判断是否设置了标志位
                print('[%s] running.....'%name)
                time.sleep(1)
            else:
                print('[%s] sees red light,waiting...'%name)
                event.wait()
                print('[%s] green light is on,start going...'%name)
    
    
    # startTime = time.time()
    light = threading.Thread(target=lighter,)
    light.start()
    
    car = threading.Thread(target=car,args=('MINT',))
    car.start()
    endTime = time.time()
    # print('用时:',endTime-startTime)
    
    '''
                               GIL  全局解释器
            在非python环境中,单核情况下,同时只能有一个任务执行。多核时可以支持多个线程同时执行。但是在python中,无论有多少个核
            同时只能执行一个线程。究其原因,这就是由于GIL的存在导致的。
            GIL的全程是全局解释器,来源是python设计之初的考虑,为了数据安全所做的决定。某个线程想要执行,必须先拿到GIL,我们可以
            把GIL看做是“通行证”,并且在一个python进程之中,GIL只有一个。拿不到线程的通行证,并且在一个python进程中,GIL只有一个,
            拿不到通行证的线程,就不允许进入CPU执行。GIL只在cpython中才有,因为cpython调用的是c语言的原生线程,所以他不能直接操
            作cpu,而只能利用GIL保证同一时间只能有一个线程拿到数据。而在pypy和jpython中是没有GIL的
            python在使用多线程的时候,调用的是c语言的原生过程。
    '''
    '''
                                python针对不同类型的代码执行效率也是不同的
            1、CPU密集型代码(各种循环处理、计算等),在这种情况下,由于计算工作多,ticks技术很快就会达到阀值,然后出发GIL的
            释放与再竞争(多个线程来回切换当然是需要消耗资源的),所以python下的多线程对CPU密集型代码并不友好。
            2、IO密集型代码(文件处理、网络爬虫等设计文件读写操作),多线程能够有效提升效率(单线程下有IO操作会进行IO等待,
            造成不必要的时间浪费,而开启多线程能在线程A等待时,自动切换到线程B,可以不浪费CPU的资源,从而能提升程序的执行
            效率)。所以python的多线程对IO密集型代码比较友好。
    '''
    '''
        主要要看任务的类型,我们把任务分为I/O密集型和计算密集型,而多线程在切换中又分为I/O切换和时间切换。如果任务属于是I/O密集型,
        若不采用多线程,我们在进行I/O操作时,势必要等待前面一个I/O任务完成后面的I/O任务才能进行,在这个等待的过程中,CPU处于等待
        状态,这时如果采用多线程的话,刚好可以切换到进行另一个I/O任务。这样就刚好可以充分利用CPU避免CPU处于闲置状态,提高效率。但是
        如果多线程任务都是计算型,CPU会一直在进行工作,直到一定的时间后采取多线程时间切换的方式进行切换线程,此时CPU一直处于工作状态,
        此种情况下并不能提高性能,相反在切换多线程任务时,可能还会造成时间和资源的浪费,导致效能下降。这就是造成上面两种多线程结果不能的解释。
    结论:I/O密集型任务,建议采取多线程,还可以采用多进程+协程的方式(例如:爬虫多采用多线程处理爬取的数据);对于计算密集型任务,python此时就不适用了。
    '''
    
    
    展开全文
  • python多线程

    千次阅读 2019-10-12 11:20:59
    python多线程及notify和wait的是使用python多线程多线程创建方式多线程管理 python多线程 python主要是通过thread和threading这两个模块来实现多线程支持。python的thread模块是比较底层的模块,python的threading...

    python多线程及notify和wait使用

    python多线程

    python主要是通过thread和threading这两个模块来实现多线程支持。python的thread模块是比较底层的模块,python的threading模块是对thread做了一些封装,可以更加方便的被使用。但是python由于GIL(global interpreter lock 全局解释锁)的存在无法使用threading充分利用CPU资源,GIL使得python同一个时刻只有一个线程在一个cpu上执行字节码,并且无法将多个线程映射到多个cpu上,即不能发挥多个cpu的优势。即多线程只能在一个CPU上执行,CPU是按照时间片轮询的方式来执行子线程的。

    多线程创建方式

    1. 使用Thread类进行创建
    from threading import Thread
    t = Thread(target=function_name, args=(parameter1, parameterN))
    t.start()
    

    function_name为启动线程的名字,parameter1, parameterN为对应的参数

    1. 直接继承Thread类进行创建
    from threading import Thread
    # 创建一个类,必须要继承Thread
    class MyThread(Thread):
        # 继承Thread的类,需要实现run方法,线程就是从这个方法开始的
        def run(self):
            # 具体的逻辑
            function_name(self.parameter1)
    
        def __init__(self, parameter1):
            # 需要执行父类的初始化方法
            Thread.__init__(self)
            # 如果有参数,可以封装在类里面
            self.parameter1 = parameter1
    
    # 如果有参数,实例化的时候需要把参数传递过去
    t = MyThread(parameter1)
    # 同样使用start()来启动线程
    t.start()
    
    1. 使用Thread中Timer创建循环定时线程
    import threading
    def heartBeat(self):
    	heartThread = thrreading.Timer(5,heartBeat)
    

    多线程管理

    1. 锁机制
      由于线程之间随机调度:某线程可能在执行n条后,CPU接着执行其他线程。为了多个线程同时操作一个内存中的资源时不产生混乱,我们使用锁。
      Lock(指令锁)是可用的最低级的同步指令。Lock处于锁定状态时,不被特定的线程拥有。Lock包含两种状态——锁定和非锁定,以及两个基本的方法。
      可以认为Lock有一个锁定池,当线程请求锁定时,将线程至于池中,直到获得锁定后出池。池中的线程处于状态图中的同步阻塞状态。
      实现方法:
        acquire(): 尝试获得锁定。使线程进入同步阻塞状态。
        release(): 释放锁。使用前线程必须已获得锁定,否则将抛出异常。
      以更新订单簿和删除订单簿为例,更新和删除相同orderBookId下的订单簿操作,需要在更新和删除进行加锁处理,保证在同一时刻只能进行更新或者删除操作。
      但不同的orderBookId下的订单簿更新和删除是可以同步进行的,所以加锁的维度是给每一个orderBookId分配锁,而不是所有的orderBookId共享一个锁;
    import threading
    class OrderBookManger(object):
    	def __init__(self):
    		self.__lockManger = {}
    	def addOrderBook(self,orderBookId):
    		self.__lockManger[orderBookId] = threading.LOCK()
    	def update(self,orderBookId):
    		self.__lockManger[orderBookId].acquire()
    		##to do somthing
    		self.self.__lockManger[orderBookId].release()
    	def delete(self,orderBookId):
    		self.__lockManger[orderBookId].acquire()
    		##to do somthing
    		self.self.__lockManger[orderBookId].release()
    	
    
    1. condition类及wait和notify方法
      当小伙伴a在往火锅里面添加鱼丸,这个就是生产者行为;另外一个小伙伴b在吃掉鱼丸就是消费者行为。当火锅里面鱼丸达到一定数量加满后b才能吃,这就是一种条件判断了,需要用到condition类。
      除了Lock带有的锁定池外,Condition还包含一个等待池,池中的线程处于状态图中的等待阻塞状态,直到另一个线程调用notify()/notifyAll()通知;得到通知后线程进入锁定池等待锁定。
      condition类包含的操作:
      acquire(): 线程锁
      release(): 释放锁
      wait(timeout): 线程挂起,并且释放锁,直到收到一个notify通知或者超时(可选的,浮点数,单位是秒s)才会被唤醒继续运行。wait()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。
      notify(n=1): 通知其他线程,那些挂起的线程接到这个通知之后会开始运行,默认是通知一个正等待该condition的线程,最多则唤醒n个等待的线程。notify()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。notify()不会主动释放Lock。
      notifyAll(): 如果wait状态线程比较多,notifyAll的作用就是通知所有线程

    正常唤醒场景:当a同学往火锅里面添加鱼丸加满后(最多5个,加满后通知b去吃掉),通知b同学去吃掉鱼丸(吃到0的时候通知a同学继续添加)

    ##生产者消费者举例
    # coding=utf-8
    import threading
    import time
    
    con = threading.Condition()
    
    num = 0
    
    # 生产者
    class Producer(threading.Thread):
    
        def __init__(self):
            threading.Thread.__init__(self)
    
        def run(self):
            # 锁定线程
            global num
            con.acquire()  ##锁定线程,消费者代码无法同步运行
            while True:
                print "开始添加!!!"  #<2>
                num += 1
                print "火锅里面鱼丸个数:%s" % str(num)
                time.sleep(1)
                if num >= 5:
                    print "火锅里面里面鱼丸数量已经到达5个,无法添加了!"
                    # 唤醒处于等待的线程,消费者线程会被唤醒<1>代码处,但notify不释放锁,所以此时消费者还未拿到锁
                    con.notify()  
                    # 等待通知,并释放锁,则消费者拿到锁,开始运行<1>处代码
                    con.wait()
            # 释放锁
            con.release()
    
    # 消费者
    class Consumers(threading.Thread):
        def __init__(self):
            threading.Thread.__init__(self)
    
        def run(self):
            con.acquire()
            global num
            while True:
                print "开始吃啦!!!"   ##<1>
                num -= 1
                print "火锅里面剩余鱼丸数量:%s" %str(num)
                time.sleep(2)
                if num <= 0:
                    print "锅底没货了,赶紧加鱼丸吧!"
                    con.notify()  # 唤醒生产者线程<2>
                    # 等待通知,释放锁,开始运行生产者<2>处代码
                    con.wait()
            con.release()
    
    p = Producer()
    c = Consumers()
    p.start()
    c.start()
    

    上述情况,生产者和消费者在同一个锁定池中,当生产者获取锁之后,消费者代码不能执行,直到生产者释放锁之后才能进行;需要注意的是notify不会释放锁,一定要在notify之后增加释放锁的操作。

    异常情况:唤醒和等待动作处于不同的锁定池中,会出现无法唤醒wait状态线程。下述场景fetch操作从队列中取数据当队列为空时进行fetch操作进行等待挂起;put操作往队列中添加数据

    import threading,queue
    class BaseStrategy():
    	def __init__(self):
    		self.quote_td = threading.Thread(target=self.fetch)
    		self.cond = threading.condition()
    		elf.quote_td.start()
    		self.msg_queue = queue.Queue()
    	
    	def fetch(self):
    		while(true):
    			self.cond.acquire()
    			if self.msg_Queue.size() == 0: ##(2)
    				self.cond.wait()           ##(4)
    			one = self.msg_queue.get()  ##(3)
    
    obj = BaseStrategy()
    def putone():
    	while(True):
    		if obj.msg_queue.size()==0:
    			obj.msg_queue.put("33)
    			obj.cond.acquire()
    			obj.cond.notify()
    			obj.cond.release()   
    		else:  ##(3)
    			obj.msg_queue.put("34)
    putone()			
    			
    

    上述代码中由于putone和fetch不在一个锁定池中,条件变量只是针对线程msg_queue,所以putone 和 fetch 会有交替执行情况,当putone函数执行到(3)时,fetch拿到执行权,执行了(3)之后,循环继续执行(2),通过语句(4)把自己挂起,这时putone拿到执行权,继续从(3)开始执行,循环后会一直走(3),就会导致fetch线程一直不会被notify。
    解决方案:目的是当队列为空时进行等待挂起,所以直接使用了队列的get(timeout=5)方法,python队列是线程安全的,每次从队列中获取数据时如果队列有数据则直接获取,否则等待5s钟,仍拿不到数据则报异常。修改后的代码如下

    import threading,queue,Queue
    class BaseStrategy():
    	def __init__(self):
    		self.quote_td = threading.Thread(target=self.fetch)
    		self.cond = threading.condition()
    		elf.quote_td.start()
    		self.msg_queue = queue.Queue()
    	def fetch(self):
    			while(true):
    				try:
    					one = self.msg_queue.get(timeout=5)
    				except Queue.Empty:
    					print("empty queue")
    					continue
    obj = BaseStrategy()
    def putone():
    	while(True):
    		obj.msg_queue.put("34)
    putone()
    			
    
    展开全文
  • Python多线程

    2019-11-28 23:08:07
    本课程主要讲解使用Python中的_thread和threading模块实现多线程编程,以及队列Queue的使用。课程中使用队列实现了生产者和消费者的程序编写。 重点:_thread和threading、Queue
  • python多线程结束线程Python threading module is used to implement multithreading in python programs. In this lesson, we will study about Thread and different functions of python threading module. ...

    python多线程结束线程

    Python threading module is used to implement multithreading in python programs. In this lesson, we will study about Thread and different functions of python threading module. Python multiprocessing is one of the similar module that we looked into sometime back.

    Python线程模块用于在python程序中实现多线程。 在本课程中,我们将研究Thread和python threading模块的不同功能。 Python多处理是我们前一段时间研究的类似模块之一。

    什么是线程? (What is a Thread?)

    In Computer Science, threads are defined as the smallest unit of work which is scheduled to be done by an Operating System.

    在《计算机科学》中,线程被定义为计划由操作系统完成的最小工作单元。

    Some points to consider about Threads are:

    有关线程的几点注意事项:

    • Threads exists inside a process.

      线程存在于进程内部。
    • Multiple threads can exist in a single process.

      一个进程中可以存在多个线程。
    • Threads in same process share the state and memory of the parent process.

      同一进程中的线程共享父进程的状态和内存。

    This was just a quick overview of Threads in general. This post will mainly focus on the threading module in Python.

    这只是一般的Thread的快速概述。 这篇文章将主要关注Python中的threading模块。

    Python线程 (Python threading)

    Let us introduce python threading module with a nice and simple example:

    让我们通过一个简单的好例子介绍python threading模块:

    import time
    from threading import Thread
    
    def sleepMe(i):
        print("Thread %i going to sleep for 5 seconds." % i)
        time.sleep(5)
        print("Thread %i is awake now." % i)
    
    for i in range(10):
        th = Thread(target=sleepMe, args=(i, ))
        th.start()

    When we run this script, the following will be the output:

    Python Threading Example, Python multithreading example

    当我们运行此脚本时,将输出以下内容:

    When you run this program, the output might be different as parallel threads doesn’t have any defined order of their life.

    当您运行此程序时,输出可能会有所不同,因为并行线程没有生命周期的任何已定义顺序。

    Python线程功能 (Python threading functions)

    We will reuse the last simple program we wrote with threading module and build up the program to show different threading functions.

    我们将重用使用threading模块编写的最后一个简单程序,并构建该程序以显示不同的线程功能。

    threading.active_count() (threading.active_count())

    This function returns the number of threads currently in execution. Let us modify the last script’s sleepMe(...) function. Our new script will look like:

    该函数返回当前正在执行的线程数。 让我们修改最后一个脚本的sleepMe(...)函数。 我们的新脚本如下所示:

    import time
    import threading
    from threading import Thread
    
    def sleepMe(i):
        print("Thread %i going to sleep for 5 seconds." % i)
        time.sleep(5)
        print("Thread %i is awake now." % i)
    
    for i in range(10):
        th = Thread(target=sleepMe, args=(i, ))
        th.start()
        print("Current Thread count: %i." % threading.active_count())

    This time, we will have a new output showing how many threads are active. Here is the output:

    Python multithreading example, python threading active count

    这次,我们将有一个新的输出,显示有多少线程处于活动状态。 这是输出:

    Note that active thread count, after all 10 threads has started is not 10 but 11. This is because it also counts the main thread inside from other 10 threads were spawned.

    请注意,在所有10个线程启动之后,活动线程数不是10而是11 。 这是因为它还计算生成的其他10个线程中的主线程。

    threading.current_thread() (threading.current_thread())

    This function returns the current thread in execution. Using this method, we can perform particular actions with the obtained thread. Let us modify our script to use this method now:

    该函数返回正在执行的当前线程。 使用此方法,我们可以对获得的线程执行特定的操作。 让我们修改脚本以立即使用此方法:

    import time
    import threading
    from threading import Thread
    
    def sleepMe(i):
        print("Thread %s going to sleep for 5 seconds." % threading.current_thread())
        time.sleep(5)
        print("Thread %s is awake now.\n" % threading.current_thread())
    
    #Creating only four threads for now
    for i in range(4):
        th = Thread(target=sleepMe, args=(i, ))
        th.start()

    The output of the above script will be:

    Python Threading Current Thread

    上面脚本的输出将是:

    threading.main_thread() (threading.main_thread())

    This function returns the main thread of this program. More threads can be spawned form this thread. Let us see this script:

    该函数返回该程序的主线程。 可以从该线程中产生更多线程。 让我们看一下这个脚本:

    import threading
    print(threading.main_thread())

    Now, let’s run this script:

    Python Main Thread

    现在,让我们运行以下脚本:

    As shown in the image, it is worth noticing that the main_thread() function was only introduced in Python 3. So take care that you use this function only when using Python 3+ versions.

    如图所示,值得注意的是main_thread()函数仅在Python 3中引入。因此请注意,仅在使用Python 3+版本时才使用此函数。

    threading.enumerate() (threading.enumerate())

    This function returns a list of all active threads. It is easy to use. Let us write a script to put it in use:

    此函数返回所有活动线程的列表。 它很容易使用。 让我们编写一个脚本来使用它:

    import threading
    for thread in threading.enumerate():
        print("Thread name is %s." % thread.getName())

    Now, let’s run this script:

    Python Threading Enumerate

    现在,让我们运行以下脚本:

    We were having only Main thread when we executed this script, hence the output.

    执行此脚本时只有主线程,因此只有输出。

    threading.Timer() (threading.Timer())

    This function of threading module is used to create a new Thread and letting it know that it should only start after a specified time. Once it starts, it should call the specified function. Let’s study it with an example:

    threading模块的此功能用于创建新的线程,并使其仅在指定时间后启动。 一旦启动,它应该调用指定的函数。 让我们用一个例子来研究它:

    import threading
    
    def delayed():
        print("I am printed after 5 seconds!")
    
    thread = threading.Timer(3, delayed)
    thread.start()

    Now, let’s run this script:

    Python Threading Timer

    现在,让我们运行以下脚本:

    Python多线程 (Python Multithreading)

    In this post, we saw some functions in the threading module in Python and how it provides convenient methods to control Threads in a multithreaded environment.

    在这篇文章中,我们看到了Python threading模块中的一些功能,以及它如何提供方便的方法来控制多线程环境中的线程。

    Reference: API Doc

    参考: API文档

    翻译自: https://www.journaldev.com/17290/python-threading-multithreading

    python多线程结束线程

    展开全文
  • 对于python 多线程的理解,我花了很长时间,搜索的大部份文章都不够通俗易懂。所以,这里力图用简单的例子,让你对多线程有个初步的认识。 单线程  在好些年前的MS-DOS时代,操作系统处理问题都是单任务的,我想做...
  • 理理解解python多多线线程程 python多多线线程程简简明明教教程程 这篇文章主要介绍了理解python多线程,一个快速理解python多线程的简明教程,需要的朋友可以参考下 对于python 多线程的理解 花了很长时间搜索的大部...
  • python多线程教程:python多线程详解

    千次阅读 2020-02-03 11:49:20
    文章目录一、线程介绍二...python多线程详解 一、线程介绍 什么是线程 线程(Thread)也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际运作单位。线程自己不拥有系统资源...


    python多线程详解

    一、线程介绍

    什么是线程
    线程(Thread)也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际运作单位。线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。

    为什么要使用多线程
    线程在程序中是独立的、并发的执行流。与分隔的进程相比,进程中线程之间的隔离程度要小,它们共享内存、文件句柄和其他进程应有的状态。

    因为线程的划分尺度小于进程,使得多线程程序的并发性高。进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

    线程比进程具有更高的性能,这是由于同一个进程中的线程都有共性多个线程共享同一个进程的虚拟空间。线程共享的环境包括进程代码段、进程的公有数据等,利用这些共享的数据,线程之间很容易实现通信。

    操作系统在创建进程时,必须为该进程分配独立的内存空间,并分配大量的相关资源,但创建线程则简单得多。因此,使用多线程来实现并发比使用多进程的性能要高得多。

    总结起来,使用多线程编程具有如下几个优点:

    进程之间不能共享内存,但线程之间共享内存非常容易。

    操作系统在创建进程时,需要为该进程重新分配系统资源,但创建线程的代价则小得多。因此,使用多线程来实现多任务并发执行比使用多进程的效率高。

    Python 语言内置了多线程功能支持,而不是单纯地作为底层操作系统的调度方式,从而简化了 Python 的多线程编程。
    **

    给大家推荐一个python学习交流裙:913 ###066口口口266,每天都学习资料分享

    **

    二、线程实现

    threading模块

    普通创建方式

    i
    mport threading
    import time
    
    def run(n):
        print("task", n)
        time.sleep(1)
        print('2s')
        time.sleep(1)
        print('1s')
        time.sleep(1)
        print('0s')
        time.sleep(1)
    
    if __name__ == '__main__':
        t1 = threading.Thread(target=run, args=("t1",))
        t2 = threading.Thread(target=run, args=("t2",))
        t1.start()
        t2.start()
    
    ----------------------------------
    
    >>> task t1
    >>> task t2
    >>> 2s
    >>> 2s
    >>> 1s
    >>> 1s
    >>> 0s
    >>> 0s
    > 这里是引用
    

    自定义线程

    继承threading.Thread来自定义线程类,其本质是重构Thread类中的run方法

    import threading
    import time
    
    class MyThread(threading.Thread):
        def __init__(self, n):
            super(MyThread, self).__init__()  # 重构run函数必须要写
            self.n = n
    
        def run(self):
            print("task", self.n)
            time.sleep(1)
            print('2s')
            time.sleep(1)
            print('1s')
            time.sleep(1)
            print('0s')
            time.sleep(1)
    
    if __name__ == "__main__":
        t1 = MyThread("t1")
        t2 = MyThread("t2")
        t1.start()
        t2.start()
        
    ----------------------------------
    
    >>> task t1
    >>> task t2
    >>> 2s
    >>> 2s
    >>> 1s
    >>> 1s
    >>> 0s
    >>> 0s
    

    守护线程

    我们看下面这个例子,这里使用setDaemon(True)把所有的子线程都变成了主线程的守护线程,因此当主进程结束后,子线程也会随之结束。所以当主线程结束后,整个程序就退出了。

    import threading
    import time
    
    def run(n):
        print("task", n)
        time.sleep(1)       #此时子线程停1s
        print('3')
        time.sleep(1)
        print('2')
        time.sleep(1)
        print('1')
    
    if __name__ == '__main__':
        t = threading.Thread(target=run, args=("t1",))
        t.setDaemon(True)   #把子进程设置为守护线程,必须在start()之前设置
        t.start()
        print("end")
        
    ----------------------------------
    
    >>> task t1
    >>> end
    

    我们可以发现,设置守护线程之后,当主线程结束时,子线程也将立即结束,不再执行。

    主线程等待子线程结束

    为了让守护线程执行结束之后,主线程再结束,我们可以使用join方法,让主线程等待子线程执行。

    import threading
    import time
    
    def run(n):
        print("task", n)
        time.sleep(1)       #此时子线程停1s
        print('3')
        time.sleep(1)
        print('2')
        time.sleep(1)
        print('1')
    
    if __name__ == '__main__':
        t = threading.Thread(target=run, args=("t1",))
        t.setDaemon(True)   #把子进程设置为守护线程,必须在start()之前设置
        t.start()
        t.join() # 设置主线程等待子线程结束
        print("end")
    
    ----------------------------------
    
    >>> task t1
    >>> 3
    >>> 2
    >>> 1
    >>> end
    

    多线程共享全局变量

    线程是进程的执行单元,进程是系统分配资源的最小单位,所以在同一个进程中的多线程是共享资源的。

    import threading
    import time
    
    g_num = 100
    
    def work1():
        global g_num
        for i in range(3):
            g_num += 1
        print("in work1 g_num is : %d" % g_num)
    
    def work2():
        global g_num
        print("in work2 g_num is : %d" % g_num)
    
    if __name__ == '__main__':
        t1 = threading.Thread(target=work1)
        t1.start()
        time.sleep(1)
        t2 = threading.Thread(target=work2)
        t2.start()
    
    ----------------------------------
    
    >>> in work1 g_num is : 103
    >>> in work2 g_num is : 103
    

    互斥锁
    由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁,即同一时刻允许一个线程执行操作。线程锁用于锁定资源,你可以定义多个锁, 像下面的代码, 当你需要独占某一资源时,任何一个锁都可以锁这个资源,就好比你用不同的锁都可以把相同的一个门锁住是一个道理。

    由于线程之间是进行随机调度,如果有多个线程同时操作一个对象,如果没有很好地保护该对象,会造成程序结果的不可预期,我们也称此为“线程不安全”。

    为了方式上面情况的发生,就出现了互斥锁

    (Lock)from threading import Thread,Lock
    import os,time
    def work():
        global n
        lock.acquire()
        temp=n
        time.sleep(0.1)
        n=temp-1
        lock.release()
    if __name__ == '__main__':
        lock=Lock()
        n=100
        l=[]
        for i in range(100):
            p=Thread(target=work)
            l.append(p)
            p.start()
        for p in l:
            p.join()
    

    递归锁

    RLcok类的用法和Lock类一模一样,但它支持嵌套,在多个锁没有释放的时候一般会使用RLcok类。

    import threading
    import time
    
    def Func(lock):
        global gl_num
        lock.acquire()
        gl_num += 1
        time.sleep(1)
        print(gl_num)
        lock.release()
    
    if __name__ == '__main__':
        gl_num = 0
        lock = threading.RLock()
        for i in range(10):
            t = threading.Thread(target=Func, args=(lock,))
            t.start()
    

    信号量(BoundedSemaphore类)
    互斥锁同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。

    import threading
    import time
    
    def run(n, semaphore):
        semaphore.acquire()   #加锁
        time.sleep(1)
        print("run the thread:%s\n" % n)
        semaphore.release()     #释放
    
    if __name__ == '__main__':
        num = 0
        semaphore = threading.BoundedSemaphore(5)  # 最多允许5个线程同时运行
        for i in range(22):
            t = threading.Thread(target=run, args=("t-%s" % i, semaphore))
            t.start()
        while threading.active_count() != 1:
            pass  # print threading.active_count()
        else:
            print('-----all threads done-----')
    

    事件(Event类)

    python线程的事件用于主线程控制其他线程的执行,事件是一个简单的线程同步对象,其主要提供以下几个方法:

    clear 将flag设置为“False”
    set 将flag设置为“True”
    is_set 判断是否设置了flag
    wait 会一直监听flag,如果没有检测到flag就一直处于阻塞状态
    事件处理的机制:全局定义了一个“Flag”,当flag值为“False”,那么event.wait()就会阻塞,当flag值为“True”,那么event.wait()便不再阻塞。

    #利用Event类模拟红绿灯
    import threading
    import time
    
    event = threading.Event()
    
    
    def lighter():
        count = 0
        event.set()     #初始值为绿灯
        while True:
            if 5 < count <=10 :
                event.clear()  # 红灯,清除标志位
                print("\33[41;1mred light is on...\033[0m")
            elif count > 10:
                event.set()  # 绿灯,设置标志位
                count = 0
            else:
                print("\33[42;1mgreen light is on...\033[0m")
    
            time.sleep(1)
            count += 1
    
    def car(name):
        while True:
            if event.is_set():      #判断是否设置了标志位
                print("[%s] running..."%name)
                time.sleep(1)
            else:
                print("[%s] sees red light,waiting..."%name)
                event.wait()
                print("[%s] green light is on,start going..."%name)
    
    light = threading.Thread(target=lighter,)
    light.start()
    
    car = threading.Thread(target=car,args=("MINI",))
    car.start()
    

    三、GIL(Global Interpreter Lock)全局解释器锁

    1、CPU密集型代码(各种循环处理、计算等等),在这种情况下,由于计算工作多,ticks计数很快就会达到阈值,然后触发GIL的释放与再竞争(多个线程来回切换当然是需要消耗资源的),所以python下的多线程对CPU密集型代码并不友好。
    2、IO密集型代码(文件处理、网络爬虫等涉及文件读写的操作),多线程能够有效提升效率(单线程下有IO操作会进行IO等待,造成不必要的时间浪费,而开启多线程能在线程A等待时,自动切换到线程B,可以不浪费CPU的资源,从而能提升程序执行效率)。所以python的多线程对IO密集型代码比较友好。

    使用建议?

    python下想要充分利用多核CPU,就用多进程。因为每个进程有各自独立的GIL,互不干扰,这样就可以真正意义上的并行执行,在python中,多进程的执行效率优于多线程(仅仅针对多核CPU而言)。

    GIL在python中的版本差异:

    1、在python2.x里,GIL的释放逻辑是当前线程遇见IO操作或者ticks计数达到100时进行释放。(ticks可以看作是python自身的一个计数器,专门做用于GIL,每次释放后归零,这个计数可以通过sys.setcheckinterval 来调整)。而每次释放GIL锁,线程进行锁竞争、切换线程,会消耗资源。并且由于GIL锁存在,python里一个进程永远只能同时执行一个线程(拿到GIL的线程才能执行),这就是为什么在多核CPU上,python的多线程效率并不高。
    2、在python3.x中,GIL不使用ticks计数,改为使用计时器(执行时间达到阈值后,当前线程释放GIL),这样对CPU密集型程序更加友好,但依然没有解决GIL导致的同一时间只能执行一个线程的问题,所以效率依然不尽如人意。

    展开全文
  • python多线程压测demo

    2021-08-08 10:56:40
    python多线程压测demo
  • python多线程场景示例

    2021-04-22 19:17:19
    python多线程场景示例
  • 主要介绍了Python多线程编程之多线程加锁操作,涉及Python线程创建、加锁、释放锁等相关操作技巧,需要的朋友可以参考下
  • python多线程代码

    2019-03-30 10:57:50
    python多线程代码
  • Python多线程实例教程

    2021-01-20 05:08:37
    在早期的Python多线程实现中,采用了thread模块。例如:  from time import ctime,sleep from thread import start_new_thread def loop1(): print enter loop1:,ctime(); sleep(3); print leave loop1
  • python 多线程脚本

    2018-10-08 15:56:41
    python 多线程封装脚本,可以直接拿来当lib导入使用。
  • python 多线程应用介绍

    2020-12-24 04:45:20
    美中不足的是,python的运行在python 虚拟机上,创建的多线程可能是虚拟的线程,需要由python虚拟机来轮询调度,这大大降低了python多线程的可用性。我们经今天用了经典的生产者和消费者的问题来说明下python的多...
  • python多线程操作实例

    2020-12-23 20:01:50
    一、python多线程 因为CPython的实现使用了Global Interpereter Lock(GIL),使得python中同一时刻只有一个线程在执行,从而简化了python解释器的实现,且python对象模型天然地线程安全。如果你想你的应用程序在多核...
  • Python 多线程实例详解

    2020-09-21 09:44:13
    主要介绍了Python 多线程实例详解的相关资料,需要的朋友可以参考下
  • 关于python多进程多线程的相关基础知识,在我之前的博客有写过,并且就关于python多线程的GIL锁问题,也在我的一篇博客中有相关的解释。 为什么python多线程在面对IO密集型任务的时候会产生加速作用? 为什么python...
  • python 多线程重启方法

    2020-09-19 14:50:51
    今天小编就为大家分享一篇python 多线程重启方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 主要介绍了Python多线程下载文件的方法,涉及Python多线程及文件操作的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
  • 主要介绍了Python多线程原理与用法,简单描述了多线程的概念、原理并结合实例形式分析了Python多线程创建、启动、各种锁机制、队列及相关函数使用技巧,需要的朋友可以参考下
  • 主要介绍了python多线程使用方法,结合实例形式详细分析了Python多线程thread模块、锁机制相关使用技巧与操作注意事项,需要的朋友可以参考下
  • 多线程可简单理解为同时执行多个任务。本文给大家分享Python 多线程Threading初学教程实例详解,感兴趣的朋友一起学习吧

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 240,727
精华内容 96,290
关键字:

python多线程

python 订阅