【Python多线程编程——threading模块】—— Python多线程系列文章(一)


前言

在日常的开发中经常会用到多线程和多进程编程,使用多线程编程可降低程序的复杂度,使程序更简洁高效。

线程是程序执行流的最小单元,是进程的一个实体,一个进程可以拥有多个线程,多个线程可以共享进程所拥有的资源。

线程可以提升程序的整体性能,一般分为内核线程和用户线程,内核线程由操作系统内核创建和撤销,用户线程不需要内核支持,是在用户程序中实现的线程。

需要注意的是:线程不能独立运行,他必须依附于进程;线程可以被抢占(中断)和暂时搁置(休眠)。


threading模块

(一)简介

在 python3 中有两种实现多线程编程的模块。

  1. _thread模块。python2中使用了thread模块实现,而 python3 不再使用该模块,为实现兼容在 python3 中将该模块改为了 _thread 模块。
  2. threading模块。因为 _thread 模块提供的是一个简单低级的线程和锁,但 threading 模块是基于 Java 的线程模块设计,相较于 _thread 更高级,所以本文只讲解 threading 模块。

其实python并不适合做多线程的开发,因为 python 解释器使用了内部的全局解释器锁(GIL锁),使得在无论何时计算机只会允许在处理器上运行单个线程,即便多核GPU也是如此(即GIL锁同一时刻只允许一个进程只有一个线程被CPU调度),所以它的效率较其他语言低。

threading 模块创建线程的方式与 Java 类似,都是采用的类来创建线程。

threading模块的函数:

函数 说明
threading.active_count() 返回正运行的线程数量(包括主线程),与len(threading.enumerate())结果相同
threading.current_thread() 返回当前线程的变量
threading.main_thread() 返回主线程
threading.enumerate() 返回一个正在运行的线程的列表

(二)创建线程—start()方法

方法一:

扫描二维码关注公众号,回复: 14700423 查看本文章

在创建线程时必须先定义一个继承threading.Thread的类,然后重写子类中的run()方法,使用
start()方法启动线程。

import threading

class threadTest(threading.Thread):  #类必须继承threading.Thread
    
    def __init__(self,args) -> None:  #args为传入线程的参数,可根据自己的需求进行定义
        
        super(threadTest,self).__init__()  #初始化super()内的必须与类名一样
        self.args = args

    def run(self) -> None:  #定义run()方法,主要写线程的执行内容

        print('test thread running......')
        print('args:',self.args)
        return super().run()

if __name__ == '__main__':
    test = threadTest('just test')  #实例化
    test.start()  #启动线程,即运行run()方法

方法二:

使用函数的方式创建线程。

import threading

def threadTest(arg):
    print('test thread running......')
    print('args:',arg)

if __name__ == '__main__':
    # target 传入函数名,注意不要写参数;args target传入的函数需要传入的参数,注意传入参数以元组的形式
    thread = threading.Thread(target=threadTest,args=('just test',))
    thread.start()  #启动线程

两种方法的结果都一样:

test thread running......
args: just test

需要注意的是:创建的线程为子线程,是主线程创建的子线程。

除 start() 方法外,threading.Thread类还提供了以下方法:

方法 说明
join(timeout) 表示主线程等待子线程timeout时长(s)后子线程若还未结束,就强制结束子线程,不设置则主线程会一直等待子线程结束后再结束
getName() 获取线程名
setName() 设置线程名
isAlive() 返回线程是否正在运行
ident() 获取线程标识符
setDaemon(bool) 设置主,子线程运行时的关系。bool为True时主线程结束,子线程立即结束;为false主,子线程运行毫不相关,独立运行

(三)join()方法

jion()常用于控制线程的运行方法,只能在线程启动后使用,设置主线程是否等待子线程的结束。

未使用join()方法:

import threading
import time

class threadTest(threading.Thread):  #类必须继承threading.Thread
    
    def __init__(self) -> None:  #args为传入线程的参数,可根据自己的需求进行定义
        
        super(threadTest,self).__init__()  #初始化super()内的必须与类名一样

    def run(self) -> None:  #定义run()方法,主要写线程的执行内容

        print('子线程' + self.getName() + '开始:' + str(time.time()))
        time.sleep(1)  #休眠1s
        print('子线程' + self.getName() + '结束:' + str(time.time()))
        
        return super().run()

if __name__ == '__main__':

    threads = [] #创建线程列表

    for i in range(1,5):
        test = threadTest()
        test.setName('Thread-%s'%(str(i))) #设置线程名称
        threads.append(test) 

    for thread in threads:
        thread.start()  #启动线程

print('主线程已结束:%s'%(str(time.time())))
  

运行结果:

子线程Thread-1开始:1652286540.3881922
子线程Thread-2开始:1652286540.3883848
子线程Thread-3开始:1652286540.388582
子线程Thread-4开始:1652286540.3887677
主线程已结束:1652286540.3887904
子线程Thread-1结束:1652286541.3895423
子线程Thread-2结束:1652286541.3897188
子线程Thread-3结束:1652286541.3898888
子线程Thread-4结束:1652286541.3902392

可以看到未使用join()方法时,多个子线程几乎是同时创建,同时结束的,并且主线程并没有等子线程结束就已经结束了。
下面是使用了join()方法。

import threading
import time

class threadTest(threading.Thread):  #类必须继承threading.Thread
    
    def __init__(self) -> None:  #args为传入线程的参数,可根据自己的需求进行定义
        
        super(threadTest,self).__init__()  #初始化super()内的必须与类名一样

    def run(self) -> None:  #定义run()方法,主要写线程的执行内容

        print('子线程' + self.getName() + '开始:' + str(time.time()))
        time.sleep(1)  #休眠1s
        print('子线程' + self.getName() + '结束:' + str(time.time()))
        
        return super().run()

if __name__ == '__main__':

    threads = [] #创建线程列表

    for i in range(1,5):
        test = threadTest()
        test.setName('Thread-%s'%(str(i))) #设置线程名称
        threads.append(test) 

    for thread in threads:
        thread.start()  #启动线程
        thread.join()

print('主线程已结束:%s'%(str(time.time())))

运行结果:

子线程Thread-1开始:1652286834.7727253
子线程Thread-1结束:1652286835.7734482
子线程Thread-2开始:1652286835.7740881
子线程Thread-2结束:1652286836.7755718
子线程Thread-3开始:1652286836.7760375
子线程Thread-3结束:1652286837.7775867
子线程Thread-4开始:1652286837.778077
子线程Thread-4结束:1652286838.779412
主线程已结束:1652286838.7796373

可以看到使用了join()后线程是依次运行的,且主线程是等待子线程结束后再结束的。

(四)setDaemon(bool)

setDaemon(bool)方法用于设置主线程的守护线程,在启动线程启动之前使用。

当bool为True时,该线程为守护线程,主线程结束,子线程立即结束;为false主,子线程运行毫不相关,独立运行,子线程继续运行到结束。示例如下:

import threading
import time

class threadTest(threading.Thread):  #类必须继承threading.Thread
    
    def __init__(self) -> None:  #args为传入线程的参数,可根据自己的需求进行定义
        
        super(threadTest,self).__init__()  #初始化super()内的必须与类名一样

    def run(self) -> None:  #定义run()方法,主要写线程的执行内容

        print('子线程' + self.getName() + '开始:' + str(time.time()))
        time.sleep(3)  #休眠2s
        print('子线程' + self.getName() + '结束:' + str(time.time()))
        
        return super().run()

if __name__ == '__main__':

    print('主线程开始:%s'%(str(time.time())))
    thread = threadTest()
    thread.setName('Thread-1') #设置线程名称
    thread.setDaemon(False) #参数设置为False
    thread.start()  #启动线程
    time.sleep(1)
    print('主线程已结束:%s'%(str(time.time())))

运行结果:

主线程开始:1652287657.6037383
子线程Thread-1开始:1652287657.6039832
主线程已结束:1652287658.6050904
子线程Thread-1结束:1652287660.6057055

可以看到bool为false主线程结束,子线程继续运行到结束。

import threading
import time

class threadTest(threading.Thread):  #类必须继承threading.Thread
    
    def __init__(self) -> None:  #args为传入线程的参数,可根据自己的需求进行定义
        
        super(threadTest,self).__init__()  #初始化super()内的必须与类名一样

    def run(self) -> None:  #定义run()方法,主要写线程的执行内容

        print('子线程' + self.getName() + '开始:' + str(time.time()))
        time.sleep(3)  #休眠2s
        print('子线程' + self.getName() + '结束:' + str(time.time()))
        
        return super().run()

if __name__ == '__main__':

    print('主线程开始:%s'%(str(time.time())))
    thread = threadTest()
    thread.setName('Thread-1') #设置线程名称
    thread.setDaemon(True) #参数设置为True
    thread.start()  #启动线程
    time.sleep(1)
    print('主线程已结束:%s'%(str(time.time())))

运行结果:

在这里插主线程开始:1652287817.3947828
子线程Thread-1开始:1652287817.3950415
主线程已结束:1652287818.396119入代码片

可以看到bool为True时,主线程一结束,子线程就立即结束。

多线程下一篇传送门:
https://blog.csdn.net/youngwyj/article/details/124833126

猜你喜欢

转载自blog.csdn.net/youngwyj/article/details/124720041
今日推荐