• python 多线程


    基础

    概念

    线程是一个基本的 CPU 执行单元。它必须依托于进程存活。一个线程是一个execution context(执行上下文),即一个 CPU 执行时所需要的一串指令

    类型

    因作用不同划分为不同的类型:

    • 主线程
    • 子线程
    • 守护线程(后台线程)
    • 前台线程

    GIL锁

    GIL只在CPython中才有,而在其他解释器PyPy和Jython中是没有GIL的。
    由于 GIL 锁存在,Python 里一个进程永远只能同时执行一个线程(拿到 GIL 的线程才能执行),这就是为什么在多核CPU上,Python 的多线程效率并不高的根本原因

    应用

    创建多线程

    Python提供两个模块进行多线程的操作,分别是thread和threading,前者是比较低级的模块,用于更底层的操作,一般应用级别的开发不常用。

    • 方法1:直接使用threading.Thread()
    import threading
    
    def run(n):
        print("current task:", n)
    
    if __name__ == "__main__":
        t1 = threading.Thread(target=run, args=("thread 1",))
        t2 = threading.Thread(target=run, args=("thread 2",))
        t1.start()
        t2.start()
    
    • 方法2:继承threading.Thread来自定义线程类,重写run方法
    import threading
    
    class MyThread(threading.Thread):
        def __init__(self, n):
            super(MyThread, self).__init__()  # 重构run函数必须要写
            self.n = n
    
        def run(self):
            print("current task:", self.n)
    
    if __name__ == "__main__":
        t1 = MyThread("thread 1")
        t2 = MyThread("thread 2")
    
        t1.start()  #start之后运行run方法
        t2.start()
    

    线程合并

    Join函数是将该线程加入到主线程中,
    依次执行每个join的线程,执行完毕后继续往下执行,不会同时执行。
    主线程结束后,子线程还在运行,join函数使得主线程等到子线程结束时才退出。

    import threading
    
    def count(n):
        while n > 0:
            n -= 1
    
    if __name__ == "__main__":
        t1 = threading.Thread(target=count, args=("100000",))
        t2 = threading.Thread(target=count, args=("100000",))
        t1.start()
        t2.start()
        # 将 t1 和 t2 加入到主线程中
        t1.join()
        t2.join()
    

    线程的同步与互斥

    线程之间数据共享的。当多个线程对某一个共享数据进行操作时,就需要考虑到线程安全问题。threading模块中定义了Lock 类,提供了互斥锁的功能来保证多线程情况下数据的正确性。

    #创建锁
    mutex = threading.Lock()
    #锁定
    mutex.acquire([timeout])
    #释放
    mutex.release()
    

    可选参数timeout, 如果设定了timeout,则在超时后通过返回值可以判断是否得到了锁,从而可以进行一些其他的处理。

    import threading
    import time
    
    num = 0
    mutex = threading.Lock()
    
    class MyThread(threading.Thread):
        def run(self):
            global num 
            time.sleep(1)
    
            if mutex.acquire(1):  
                num = num + 1
                msg = self.name + ': num value is ' + str(num)
                print(msg)
                mutex.release()
    
    if __name__ == '__main__':
        for i in range(5):
            t = MyThread()
            t.start()
    

    可重入锁(递归锁)

    满足在同一线程中多次请求同一资源的需求。Python 提供了可重入锁(RLock)。
    RLock内部维护着一个Lock和一个counter变量,counter 记录了 acquire 的次数,从而使得资源可以被多次 require。直到一个线程所有的 acquire 都被 release,其他的线程才能获得资源。

    #创建 RLock
    mutex = threading.RLock()
    
    class MyThread(threading.Thread):
        def run(self):
            if mutex.acquire(1):
                print("thread " + self.name + " get mutex")
                time.sleep(1)
                mutex.acquire()
                mutex.release()
                mutex.release()
    

    守护线程

    如果希望主线程执行完毕之后,不管子线程是否执行完毕都随着主线程一起结束。我们可以使用setDaemon(bool)函数,它跟join函数是相反的。它的作用是设置子线程是否随主线程一起结束,必须在start() 之前调用,默认为False

                class TimeLimited(Thread):  #class中的两个函数是必须的
                    def __init__(self):
                        Thread.__init__(self)
    
                    def run(self):
                        func(params)
    
                t = TimeLimited()
                t.setDaemon(True)  #这个用户线程必须设置在start()前面
                t.start()
                t.join(timeout=time_limited)
                if t.is_alive():
                    raise Exception('连接超时')
    

    定时器

    规定函数在多少秒后执行某个操作

    import threading
    def func1(a):
        print('Do something')
        a+=1
        print(a)
        print('当前线程数为{}'.format(threading.activeCount()))
        if a>5:
            return
        t=threading.Timer(5,func1,(a,))
        t.start()
    
  • 相关阅读:
    MySQL之LEFT JOIN中使用ON和WHRERE对表数据
    Mysql索引分类
    个人发展战略(二)
    个人发展战略(一)
    List的add方法与addAll方法的区别、StringBuffer的delete方法与deleteCharAt的区别
    职业理财规划
    Servlet简介与Servlet和HttpServlet运行的流程
    Ajax的get、post和ajax提交
    Ajax方法
    监听器随笔
  • 原文地址:https://www.cnblogs.com/qian-shan/p/12596134.html
Copyright © 2020-2023  润新知