首页 > 其他分享 >Pyhton多线程

Pyhton多线程

时间:2022-11-02 09:59:31浏览次数:65  
标签:__ Pyhton threading 线程 time print import 多线程

多线程介绍

什么是线程

​ 线程(Thread)也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际运作单位。

​ 个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。

为什么需要多线程

  • 进程之间不能共享内存,但线程之间共享内存非常容易。
  • 使用多线程来实现多任务并发执行比使用多进程的效率高。
  • 多个线程需要并发处理,并共享处理结果。

多线程实现方法

创建线程

1.普通创建线程方法

  • 调用threading模块:

    import threading,time
    
    def run(input):
        for i in range(10):
            print('sub task:%s'%input)
            time.sleep(1)
    
    if __name__ == '__main__':
        t = threading.Thread(target=run, args=("hello world",))
        t.start()
        for i in range(10):
            print('main task')
            time.sleep(1)    
    

2.Thread类继承方法

  • 新建类,继承自threading.Thread类:

    import threading
    import time
    
    class MyThread(threading.Thread):
        def __init__(self, input):
            super(MyThread, self).__init__()  # 重构run函数必须要写
            self.input = input
    
        def run(self):
          	for i in range(10):
                print("task", self.input)
                time.sleep(1)
    
    if __name__ == "__main__":
        t1 = MyThread("hello world 1")
        t2 = MyThread("hello world 2")
        t1.start()
        t2.start()
    

守护线程

1.设置子线程为守护线程

  • 使用setDaemon(True)把所有的子线程都变成了主线程的守护线程,因此当主进程结束后,子线程也会随之结束

    import threading
    import time
    
    def run(n):
        for i in range(10):
            print("task", self.input)
            time.sleep(1)
    
    if __name__ == '__main__':
        t = threading.Thread(target=run, args=("hello world",))
        t.setDaemon(True)   # 主线程kill,子线程自动kill
        t.start()
        print("end")
    

2.主线程等待子线程结束后执行下一步

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

    import threading
    import time
    
    def run(n):
        for i in range(10):
            print('sub task')
            time.sleep(1)
    
    if __name__ == '__main__':
        t = threading.Thread(target=run, args=("t1",))
        t.setDaemon(True)   # 主线程kill,子线程自动kill
        t.start()
        t.join()  # 主线程停止等待子线程执行完毕后,再继续执行!
                  # 注释掉之后,就是子线程、主线程同时跑!
    

3.多线程共享全局变量

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

    import threading
    import time
    g_num = 100
    
    def run(n):
        global g_num
        for i in range(10):
            print('sub task')
            g_num += 1
            time.sleep(1)
    
    if __name__ == '__main__':
        t = threading.Thread(target=run, args=("t1",))
        t.setDaemon(True)   # 主线程kill,子线程自动kill
        t.start()
        # t.join()  # 主线程停止等待子线程执行完毕后,再继续执行!
                    # 注释掉之后,就是子线程、主线程同时跑!
        for i in range(10):
            print('main task:%d'%g_num)
            time.sleep(1)    
    
    

4.互斥锁

  • 多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁,即同一时刻允许一个线程执行操作。

  • 如果有多个线程同时操作一个对象,如果没有很好地保护该对象,会造成程序结果的不可预期,我们也称此为“线程不安全”

  • 线程锁用于锁定资源,你可以定义多个锁, 像下面的代码, 当你需要独占某一资源时,任何一个锁都可以锁这个资源,就好比你用不同的锁都可以把相同的一个门锁住是一个道理。

    from threading import Thread,Lock
    import os,time,threading
    reg = 0
    
    def work1():
        global reg
    
        lock.acquire()
        for i in range(10):
            reg = i
            print(reg)
            time.sleep(0.5)
        lock.release()
    
    def work2():
        global reg
    
        lock.acquire()
        for i in range(10):
            reg = i * 10
            print(reg)
            time.sleep(0.5)
        lock.release()
    
    
    if __name__ == '__main__':
        lock=Lock()
        t1 = threading.Thread(target=work1)
        t2 = threading.Thread(target=work2)
        t1.start()
        t2.start()
        t1.join() # hold on ,wait for this thread
        t2.join() # hold on ,wait for this thread
    

5.递归锁

  • 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()
    

6.信号量

  • 互斥锁同时只允许一个线程更改数据,而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-----')
    

7.事件(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()
    
    # 前5秒是绿灯,5~10秒是红灯。
    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()
    

Python多线程内在逻

  • 在非python环境中,单核情况下,同时只能有一个任务执行。多核时可以支持多个线程同时执行。但是在python中,无论有多少核,同时只能执行一个线程。
  • GIL的全称是Global Interpreter Lock(全局解释器锁),来源是python设计之初的考虑,为了数据安全所做的决定。某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行。
  • Python多线程的工作过程:(python在使用多线程的时候,调用的是c语言的原生线程)
    • 拿到公共数据
    • 申请gil
    • python解释器调用os原生线程
    • os操作cpu执行运算
    • 当该线程执行时间到后,无论运算是否已经执行完,gil都被要求释放
    • 进而由其他进程重复上面的过程
    • 等其他进程执行完后,又会切换到之前的线程(从他记录的上下文继续执行),整个过程是每个线程执行自己的运算,当执行时间到就进行切换(context switch)。

参考教程

https://www.cnblogs.com/luyuze95/p/11289143.html

标签:__,Pyhton,threading,线程,time,print,import,多线程
From: https://www.cnblogs.com/weicun581/p/16849993.html

相关文章

  • Java多线程(7):JUC(下)
    您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~ 除了四种常见的同步器(发令枪、摇号器、栅栏和交换机),JUC还有所谓线程安全的容器、阻塞队列和一些特殊的类。其中常出现的......
  • 多线程 & 反射 & 注解 & JDBC 核心点总结
    多线程核心点:线程安全创建线程的两种方式线程生命周期获取、修改线程名获取当前线程对象静态方法sleep()通过异常终止线程的睡眠interrupt()强行终止线程合理......
  • Linux--多线程(三)
    生产者消费者模型概念:生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过一个来进行通讯,所以生产者生产完数......
  • Java多线程(7):JUC(上)
    您好,我是湘王,这是我的51CTO博客,欢迎您来,欢迎您再来~前面把线程相关的生命周期、关键字、线程池(ThreadPool)、ThreadLocal、CAS、锁和AQS都讲完了,现在就剩下怎么来用多线程了。......
  • Java多线程-ThreadPool线程池(三)
    开完一趟车完整的过程是启动、行驶和停车,但老司机都知道,真正费油的不是行驶,而是长时间的怠速、频繁地踩刹车等动作。因为在速度切换的过程中,发送机要多做一些工作,当然就要......
  • Java多线程-线程关键字(二)
    Java中和线程相关的关键字就两:volatile和synchronized。volatile以前用得较少,以后会用得更少(后面解释)。它是一种非常轻量级的同步机制,它的三大特性是:1、保证可见性,即强制......
  • C语言:---gdb多线程调试
    1)恢复程序运行和单步调试当程序被停住了,你可以用continue命令恢复程序的运行直到程序结束,或下一个断点到来。也可以使用step或next命令单步跟踪程序。continue[ignore-coun......
  • Java多线程-线程生命周期(一)
    如果要问我Java当中最难的部分是什么?最有意思的部分是什么?最多人讨论的部分是什么?那我会毫不犹豫地说:多线程。Java多线程说它难,也不难,就是有点绕;说它简单,也不简单,需要理......
  • 线程和进程的区别与联系以及单线程多进程与单进程多线程的区别
    线程和进程概念进程(process):是指具有已一定功能的独立程序,是系统资源分配的基本单位,在内存中有其完备的数据空间和代码空间,拥有完整的虚拟空间地址。一个进程所拥有的数据和......
  • Java多线程(7):JUC(上)
    您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~ 前面把线程相关的生命周期、关键字、线程池(ThreadPool)、ThreadLocal、CAS、锁和AQS都讲完了,现在就剩下怎么来用多线程了......