• python多线程threading


    python多线程threading

    目录

    threading介绍与简单使用

    join功能

    queue功能

    lock锁

    同步对象

    信号量

    threading介绍与简单使用

    threading介绍:

    threading模块
    threading 模块除了包含 _thread 模块中的所有方法外,还提供的其他方法:
    threading.currentThread(): 返回当前的线程变量。
    threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
    threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
    
    
    
    除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:
    run(): 用以表示线程活动的方法。
    start():启动线程活动。
    join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
    isAlive(): 返回线程是否活动的。
    getName(): 返回线程名。
    setName(): 设置线程名。
    

      

    程序示例:import threading


    import threading

    def thread_job():

    print("this is an added Thread ,number is %s" %threading.currentThread())


    def main():
    added_thread = threading.Thread(target=thread_job) # 定义一个新的线程,指定一个任务给target
    added_thread.start() # 开启线程
    print(threading.activeCount())
    print(threading.enumerate())
    print(threading.currentThread())


    if __name__ =='__main__':
    main()


      

     程序运行结果

    第一个输出是当前线程,这个是我们开启的线程

    第二个输出的是在正在运行的线程的数量

    第三个输出返回一个包含正在运行的线程的list,包含主线程和开启的线程

    第四个输出是当前线程,最后只剩下主线程

    join功能

    join功能介绍

    join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。

    当我们有一个程序功能必须等到开启的线程执行完以后,才能运行主线程,就可以使用这个功能。

    不加join的情况,这种情况下,以下例程序看来,主线程运行更快,我们看看结果

    程序示例1:

    import threading
    import time
    
    
    def thread_job():
    
       print("T1 start")
       for i in range(10):
           time.sleep(0.1)
       print("T1 finish")
    
    
    def main():
       added_thread = threading.Thread(target=thread_job,name = 'T1') #定义一个新的线程,指定一个任务给target
       added_thread.start()  #开启线程
       print("all done")
    
      
    
    if__name__=='__main__':
       main()
    

      

    程序运行结果

    加join的情况,等待我们开启的线程执行完以后才能运行主线程。

    程序示例2:

    import threading
    import time
    
    
    def thread_job():
    
       print("T1 start")
       for i in range(10):
           time.sleep(0.1)
       print("T1 finish")
    
    
    def main():
       added_thread = threading.Thread(target=thread_job,name = 'T1') #定义一个新的线程,指定一个任务给target
       added_thread.start()  #开启线程
       added_thread.join()
       print("all done")
    
    
    if __name__ == '__main__':
        main()
    

     

    程序运行结果

    queue功能

    线程之间的通信

    queue功能:

    线程优先级队列( Queue)
    Python 的 Queue 模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列 PriorityQueue。
    这些队列都实现了锁原语,能够在多线程中直接使用,可以使用队列来实现线程间的同步。
    Queue 模块中的常用方法:
    Queue.qsize() 返回队列的大小
    Queue.empty() 如果队列为空,返回True,反之False
    Queue.full() 如果队列满了,返回True,反之False
    Queue.full 与 maxsize 大小对应
    Queue.get([block[, timeout]])获取队列,timeout等待时间
    Queue.get_nowait() 相当Queue.get(False)
    Queue.put(item) 写入队列,timeout等待时间
    Queue.put_nowait(item) 相当Queue.put(item, False)
    Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
    Queue.join() 实际上意味着等到队列为空,再执行别的操作
    

    先进先出模式:get与put的阻塞

    #get卡
    import queue   #线程队列
    
    q = queue.Queue() #线程队列的对象
    
    q.put(12) #往队列里面放入数据
    
    q.put("hello")
    
    q.put({"name":"yuan"})
    
    #先进先出
    #如果队列为空,取值就会被阻塞,只有当队列有值才能取到值
    while 1:
        data = q.get()
        if data:
            print(data)
            print("--------")
    
    
    
    
    
    #put卡
    
    import queue   #线程队列
    
    q = queue.Queue(3) #队列里可以存储几个值
    
    q.put(12) #往队列里面放入数据
    
    q.put("hello")
    
    q.put({"name":"yuan"})
    
    q.put(1) #只能存储3个值,这里缺试图存储第四个值,只有当有别的线程取走一个值,才能存储进值
    
    
    while 1:
        data = q.get()
        if data:
            print(data)
            print("--------")

    在get与put阻塞的时候报错

    q.put(1,False)
    
    q.get(block=False)

    先进后出模式

    import queue
    
    q = queue.LifoQueue()
    
    
    q.put(12)
    
    q.put("hello")
    
    q.put({"name":"yuan"})
    
    q.put(1)
    
    while 1:
        data = q.get()
        if data:
            print(data)
            print("--------")

    优先级模式

    import queue
    
    q = queue.PriorityQueue()
    
    q.put([3,12]) #往队列里面放入数据
    
    q.put([2,"hello"])
    
    q.put([1,{"name":"yuan"}])
    
    while 1:
        data = q.get()
        if data:
            print(data)
            print("--------")

    下面演示了在多线程中怎么返回线程中的运行结果,因为不能使用return返回! 使用Queue.get()和Queue.put()方法

    程序示例

    import threading
    from queue import Queue
    
    
    def job(l,q):
        for i in range(len(l)):
            l[i] = l[i] + 1  # 对列表里每一个值加一
        q.put(l)  # 把计算的结果保存到queue
    
    
    def main():
        q = Queue()  # 使用queue存放返回值
        threads = []  # 创建进程列表
    
        data = [[1, 2], [3, 4], [4, 5], [5, 6]]
    
        # 创建四个进程并启动添加到进程列表里面
        for i in range(4):
            t = threading.Thread(target=job, args=(data[i], q))
            t.start()
            threads.append(t)
    
        # 把所有线程都加到主线程中
        for thread in threads:
            thread.join()
    
        # 创建存放结果的列表
        results = []
    
        # 把结果保存到results列表中
        for _ in range(4):
            results.append(q.get())
        print(results)
        
        
    
    
    if __name__ =='__main__':
        main()
    

      

     程序运行结果

    比较多线程和不使用多线程的运行速度

    我们知道python中实现多线程其实是把正在运行的线程锁住,这时候其他线程就不会运行,就是在同一时间里只有一个线程在运行,在不断地切换线程中就可以实现多线程。

    下面我使用多线程和不使用线程,来做同样的运算工作,看谁运行的更快。

    import threading
    from queue import Queue
    import time
    
    
    def job(l,q):
        for i in range(len(l)):
            l[i] = l[i] + 1  # 对列表里每一个值加一
        q.put(l)  # 把计算的结果保存到queue
    
    
    def normal(l):
        results = []
        for i in range(len(l)):
            l[i] = l[i] + 1
            results.append(l[i])
        return results
    
    
    
    
    def main(list):
        q = Queue()  # 使用queue存放返回值
        threads = []  # 创建进程列表
    
        # 创建四个进程并启动添加到进程列表里面
        for i in range(4):
            t = threading.Thread(target=job, args=(list[i], q))
            t.start()
            threads.append(t)
    
            # 把所有线程都加到主线程中
        for thread in threads:
            thread.join()
    
            # 创建存放结果的列表
        results = []
    
        # 把结果保存到results列表中
        for _ in range(4):
            results.append(q.get())
        print(results)
    
    
    
    
    if __name__ =='__main__':
        data1 = [[1, 2], [3, 4], [4, 5], [5, 6]]
        data2 = [[1, 2], [3, 4], [4, 5], [5, 6]]
    
        start1_time =time.time()
        main(data1)
        print(time.time()-start1_time)
    
        start2_time = time.time()
        result = []
        for i in range(len(data2)):
          result.append(normal(data2[i]))
            
        print(result)
        print(time.time()-start2_time)
    

      

    运行结果

    在pycham和网上的在线编译器上都运行过,大致上来多线程运行的速度要快不少

     

    lock锁

    lock.acquire() 锁住
    lock.release() 解锁

    #这种方式:开启100个线程,每个线程执行的时间很短,虽然线程之间有竞争关系,但在同一时刻里只有一个线程工作,每个线程执行的速度要比cpu切换的速度要快,线程的执行之间无缝连接。
    # import threading
    # def sub():
    #     global  num
    #     num -= 1
    #
    # if __name__ == '__main__':
    #     threading_list = []
    #     num = 100
    #     for i in range(100):
    #         t = threading.Thread(target=sub)
    #         t.start()
    #         threading_list.append(t)
    #     for i in threading_list:
    #         t.join()
    #     print("全部执行完成")
    #     print("num =",num)
    #这种方式:和前面不一样的是,time.sleep(0.1)的时间比cpu切换的时间慢,这样当一个线程还没有机会执行num = temp - 1,就被下一个线程拿到cpu的执行权了,
    import threading
    import time
    def sub():
        global  num
    
        temp = num
        time.sleep(0.1)
        num = temp - 1
    
    
    if __name__ == '__main__':
        threading_list = []
        num = 100
        for i in range(100):
            t = threading.Thread(target=sub)
            t.start()
            threading_list.append(t)
        for i in threading_list:
            t.join()
        print("全部执行完成")
        print("num =",num)
    #上面的问题中,因为time.sleep(0.1)的或称超过cpu切换时间,我们不需要让它切换:
    # import threading
    # import time
    # def sub():
    #     global  num
    #     lock.acquire()
    #     temp = num
    #     time.sleep(0.1)
    #     num = temp - 1
    #     lock.release()
    #
    # if __name__ == '__main__':
    #     threading_list = []
    #     num = 100
    #     lock = threading.Lock()
    #     for i in range(100):
    #         t = threading.Thread(target=sub)
    #         t.start()
    #         threading_list.append(t)
    #     for i in threading_list:
    #         t.join()
    #     print("全部执行完成")
    #     print("num =",num)
    #

    同步对象

    # import threading
    #
    # event = threading.Event //插件一个event对象
    #
    # event.wait() //如果没有设置标志位,调用wait()就会被阻塞,设置了标志位就不会被阻塞
    # event.set() //设置标志位
    # event.clear() //清除标志位
    # event.isEvent() //判断是否设置了标志位
    
    # event用来控制线程之间的执行顺序,在一个线程改变标志位,在另一个线程就能捕捉到标志位的变化
    import threading
    import time
    
    
    class Worker(threading.Thread):
        def run(self):
            event.wait()            #event.set = pass,就不会继续阻塞
            print("worker:哎。。。命苦")
            time.sleep(0.5)
            event.clear()           #清空标志位
            event.wait()            #没有标志位就会被阻塞
            print("worker:下班了")
    
    class Boss(threading.Thread):
        def run(self):
            print("Boss:今天加班到10点")
            print(event.isSet())        #False
            event.set()                 #设置标志位
            time.sleep(5)
            print("Boss:可以下班了")
            print(event.isSet())
            event.set()             #再一次设置标志位,阻塞效果消失
    
    
    if __name__ == '__main__':
        event = threading.Event()
        List = []
        for i in range(5):
            t1 = Worker()
            t1.start()
            List.append(t1)
        t2 = Boss()
        t2.start()
        List.append(t2)
        for i in List:
            i.join()

    信号量

    信号量控制最大并发数,在一段时间内有多少线程可以运行。

    import threading
    import time
    
    
    class myThread(threading.Thread):
        def run(self):
            if semaphore.acquire():
                print(self.name)
                time.sleep(3)
                semaphore.release()
    
    
    if __name__ == '__main__':
        semaphore = threading.Semaphore(5)
        threading_list = []
        num = 100
        for i in range(100):
            t = myThread()
            t.start()
            threading_list.append(t)
        for i in threading_list:
            i.join()
        print("全部执行完成")
        print("num =",num)

    解决死锁:递归锁

    # import threading
    # import time
    #
    #
    # class MyThread(threading.Thread):
    #
    #     def actionA(self):
    #         A.acquire()
    #         print(self.name,"gotA",time.ctime())
    #         time.sleep(2)
    #
    #         B.acquire()
    #         print(self.name,"gotB",time.ctime())
    #         time.sleep(1)
    #
    #         B.release()
    #         A.release()
    #
    #     def actionB(self):
    #         B.acquire()
    #         print(self.name, "gotB", time.ctime())
    #         time.sleep(2)
    #
    #         A.acquire()
    #         print(self.name, "gotA", time.ctime())
    #         time.sleep(1)
    #
    #         A.release()
    #         B.release()
    #
    #     def run(self):
    #         self.actionA()
    #         self.actionB()
    #
    # if __name__ == '__main__':
    #     A = threading.Lock()
    #     B = threading.Lock()
    #     List = []
    #     for i in range(5):
    #        t = MyThread()
    #        t.start()
    #        List.append(t)
    #     for y in List:
    #         y.join()
    #     print("All end")
    #
    
    
    #这里只有一个锁,r_lock内部是一个计数器,内部从0开始计数,当acquire一次,计数器就会加1,release就会减1
    #所以,无论何时只有一个线程拿到这个锁,用这个锁,无论再做多少次加锁、解锁的操作都是对一个锁的行为。
    #内部计数大于0,别的线程就无法拿到锁!!!
    
    
    #执行过程:五个线程竞争,有一个线程拿到cpu执行权,这个线程执行actionA,拿到r_lock锁,计数器加一,打印一次,然后再加一次锁,计数器再加一
    #线程顺序释放两把锁,这个线程是要继续往下执行actionB,r_lock锁加1,内部计数器大于0,其他线程也就拿不到这把锁了,也就保证了无论何时只有一个线程能拿到这把锁!
    #死锁的情况中,我们使用了两把锁,这里我们只使用了一把锁,而内部维持着多把锁。
    import threading
    import time
    
    
    class MyThread(threading.Thread):
    
        def actionA(self):
            r_lock.acquire()
            print(self.name,"gotA",time.ctime())
            time.sleep(2)
    
            r_lock.acquire()
            print(self.name,"gotB",time.ctime())
            time.sleep(1)
    
            r_lock.release()
            r_lock.release()
    
        def actionB(self):
            r_lock.acquire()
            print(self.name, "gotB", time.ctime())
            time.sleep(2)
    
            r_lock.acquire()
            print(self.name, "gotA", time.ctime())
            time.sleep(1)
    
            r_lock.release()
            r_lock.release()
    
        def run(self):
            self.actionA()
            self.actionB()
    
    if __name__ == '__main__':
        r_lock = threading.RLock()
        List = []
        for i in range(5):
           t = MyThread()
           t.start()
           List.append(t)
        for y in List:
            y.join()
        print("All end")
  • 相关阅读:
    electron 持续获取程序运行时间
    nfc reader iso7816 读卡器参考资料
    vue项目
    【数学】充分必要条件
    .Net 【DevExpress】 GridControl常用功能
    .Net 【基础回顾】关键字补充default
    .Net 【工作应用】 Ado.net总结
    .Net 【DevExpress】 MemoEdit总结
    发送短信封装
    Codeforces 1666 Labyrinth
  • 原文地址:https://www.cnblogs.com/-wenli/p/10161397.html
Copyright © 2020-2023  润新知