百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

玩蛇(Python) - 并发编程之多线程

moboyou 2025-06-07 16:56 23 浏览

一、线程简介

线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。

由于线程是操作系统直接支持的执行单元,因此,高级语言通常都内置多线程的支持,Python也不例外,并且,Python的线程是真正的Posix Thread,而不是模拟出来的线程。

同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。每个线程自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。

Python的线程虽然是真正的线程,但解释器执行代码时,有一个GIL锁:Global Interpreter Lock,任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。这个GIL全局锁实际上把所有线程的执行代码都给上了锁,所以多线程在Python中只能交替执行,无论多少个线程,也只能用到1个核。设计上以通过多进程实现多核任务,如果想要同时运行多个 I/O 密集型任务,则多线程仍然是一个合适的模型。

Python的标准库提供了两个模块:_thread和threading,_thread是低级模块,threading是高级模块,对_thread进行了封装。绝大多数情况下,我们只需要使用threading这个高级模块。启动一个线程就是把一个函数传入并创建Thread实例,然后调用start()开始执行。

由于任何进程默认就会启动一个线程,我们把该线程称为主线程,主线程又可以启动新的线程,Python的threading模块有个current_thread()函数,它永远返回当前线程的实例。主线程实例的名字叫MainThread,子线程的名字在创建时指定。

二、Python多线程编程实例

2.1 Thread语法

class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)

应当始终使用关键字参数调用此构造函数。 参数如下:

group:应为 None, 保留给将来实现 ThreadGroup 类的扩展使用。

target: 是用于 run() 方法调用的可调用对象。默认是 None,表示不需要调用任何方法。

name: 是线程名称。 在默认情况下,会以 "Thread-N" 的形式构造唯一名称,其中 N 为一个较小的十进制数值,或是 "Thread-N (target)" 的形式,其中 "target" 为 target.__name__,如果指定了 target 参数的话。

args: 是用于发起调用目标函数的参数列表或元组。 默认为 ()。

kwargs: 是用于调用目标函数的关键字参数字典。默认是 {}。

如果不是 None,daemon 参数将显式地设置该线程是否为守护模式。 如果是 None (默认值),线程将继承当前线程的守护模式属性。

如果子类型重载了构造函数,它一定要确保在做任何事前,先发起调用基类构造器(Thread.__init__())。

daemon:一个布尔值,表示这个线程是否是一个守护线程(True)或不是(False)。 这个值必须在调用 start() 之前设置,否则会引发 RuntimeError 。它的初始值继承自创建线程;主线程不是一个守护线程,因此所有在主线程中创建的线程默认为 daemon = False

2.2 Thread方法

  • start()

开始线程活动。它在一个线程里最多只能被调用一次。 它安排对象的 run() 方法在一个独立的控制线程中被调用。如果同一个线程对象中调用这个方法的次数大于一次,会抛出 RuntimeError 。

  • run()

代表线程活动的方法。你可以在子类型里重载这个方法。 标准的 run() 方法会对作为 target 参数传递给该对象构造器的可调用对象(如果存在)发起调用,并附带从 args 和 kwargs 参数分别获取的位置和关键字参数。使用列表或元组作为传给 Thread 的 args 参数可以达成同样的效果。

  • join(timeout=None)

等待,直到线程终结。这会阻塞调用这个方法的线程,直到被调用 join() 的线程终结。不管是正常终结还是抛出未处理异常,或者直到发生超时,超时选项是可选的。

当 timeout 参数存在而且不是 None 时,它应该是一个用于指定操作超时的以秒为单位的浮点数或者分数。因为 join() 总是返回 None ,所以你一定要在 join() 后调用 is_alive() 才能判断是否发生超时。如果线程仍然存活,则 join() 超时。

当 timeout 参数不存在或者是 None ,这个操作会阻塞直到线程终结。

一个线程可以被合并多次。如果尝试加入当前线程会导致死锁, join() 会引起 RuntimeError 异常。如果尝试 join() 一个尚未开始的线程,也会抛出相同的异常。

  • is_alive()

返回线程是否存活。当 run() 方法刚开始直到 run() 方法刚结束,这个方法返回 True 。模块函数 enumerate() 返回包含所有存活线程的列表。

2.3 定时器对象

表示一个操作应该在等待一定的时间之后运行,相当于一个定时器。 Timer 类是 Thread 类的子类,因此可以像一个自定义线程一样工作。

与线程一样,定时器也是通过调用其 Timer.start 方法来启动的。 定时器可以通过调用 cancel() 方法来停止(在其动作开始之前)。 定时器在执行其行动之前要等待的时间间隔可能与用户指定的时间间隔不完全相同。

  • class threading.Timer(interval, function, args=None, kwargs=None)

创建一个定时器,在经过 interval 秒的间隔事件后,将会用参数 args 和关键字参数 kwargs 调用 function。如果 args 为 None (默认值),则会使用一个空列表。如果 kwargs 为 None (默认值),则会使用一个空字典。

  • cancel()

停止定时器并取消执行计时器将要执行的操作。仅当计时器仍处于等待状态时有效。

2.4 进度条编程示例

2.4.1 源码

#-*- coding: UTF-8 -*-
import threading
import sys
import time
import os
#常数定义
PROGRESS_BAR_LENGTH = 101
#全局变量定义
COUNT = 1
class ThreadProgressBar (threading.Thread):
    def __init__(self, name):
        threading.Thread.__init__(self)
        self.name = name
    def run(self):
        print ("\n开始线程:" + self.name)
        normal_progress_bar()
        print ("\n退出线程:" + self.name)
def normal_progress_bar():
    global COUNT
    start_time = time.time()
    while(True):
        COUNT = COUNT + 1
        #进度100时退出        
        if COUNT >= PROGRESS_BAR_LENGTH:
            break
       
        end_time = time.time()
        #\r 表示将光标的位置回退到本行的开头位置,重新打印
        print("\r", end="")
        #带百分比进度,打印方块
        print("Download progress: {}%: ".format(COUNT), "▋" * (COUNT // 2),'[{:.2f}s]'.format(end_time-start_time), end="")
        sys.stdout.flush()
       
        #模拟IO读写时间
        time.sleep(0.05)             
   
if __name__ == '__main__':
    #打印一个提示语
    #正常处理,初始化全局变量
    COUNT = 1
    print("正常,执行进度演示".center(PROGRESS_BAR_LENGTH // 2,"-"))
    normal_progress_bar()
   
    #打印一个提示语
    print('')
    print("多线程,执行进度演示".center(PROGRESS_BAR_LENGTH // 2,"*"))
    #多线程处理,初始化全局变量
    COUNT = 1
    # 创建新线程
    threadList = []
    for i in range(os.cpu_count()):
        t = ThreadProgressBar(i)
        t.start()
        threadList.append(t)
    for t in threadList:
        t.join()

2.4.2 验证(单线程执行4.99秒,多线程执行0.31秒)

GitHub - ShanGouXueHui/PythonCases: Typical python algorithm samples

##山狗学会 License Start##

转载请注明出处,"今日头条"创作者"山狗学会“ ,注明出处即授权,未注明出处罚款100万元

主页链接:山狗学会主页

##山狗学会 License End##

相关推荐

python新手学习常见数据类型——数字

Python支持三种不同的数值类型:整型(int)、浮点型(float)、复数(complex)创建数字:a=1b=2.7c=8+4j删除数字:a=1b=2.7c=8+4...

只用一个套路公式,给 Excel 中一列人员设置随机出场顺序

很多同学会觉得Excel单个案例讲解有些碎片化,初学者未必能完全理解和掌握。不少同学都希望有一套完整的图文教学,从最基础的概念开始,一步步由简入繁、从入门到精通,系统化地讲解Excel的各个知...

Excel神技 TIME函数:3秒搞定时间拼接!职场人必学的效率秘籍

你是否经常需要在Excel中手动输入时间,或者从不同单元格拼接时、分、秒?今天我要揭秘一个超实用的Excel函数——TIME函数,它能让你3秒内生成标准时间格式,彻底告别繁琐操作!一、TIME函数基础...

销售算错数被批?97 Excel 数字函数救场,3 步搞定复杂计算

销售部小张被老板当着全部门骂。上季度销售额汇总,他把38652.78算成36852.78,差了1800块。财务对账时发现,整个部门的提成表都得重算。"连个数都算不对,还做什么销售?&...

如何使用Minitab 1分钟生成所需要的SPC数据

打开Minitab,“计算”-“随机数据”-“正太”,因为不好截图,使用的是拍照记录的方式.再要生产的行数中,填写125,可以按照要求,有些客户要求的是100个数据,就可以填写100...

验证码,除了 12306,我还没有服过谁

为了防止暴力注册或爬虫爬取等机器请求,需要验证操作者是人还是机器,便有了验证码这个设计。本文作者主要介绍了如何使用Axure来设计一个动态的图形验证码,一起来学习一下吧。在软件设计中,为了防止暴力...

零基础也能学会的9个Excel函数,小白进阶必备

今天给大家分享一些常用的函数公式,可以有效地解决Excel中办公所需,0基础也可以轻松学会。建议收藏,在需要的时候可以直接套用函数。1、计算排名根据总和,计算学生成绩排名。函数公式=RANK(E2,$...

[office] excel表格数值如何设置_excel表格怎样设置数值

excel表格数值如何设置  因为电子表格应用程序是用来处理数值数据的,所以数值格式可能是工作表中最关键的部分,格式化数值数据的方式由用户决定,但在每个工作簿的工作表之间应使用一致的处理数字的方法。...

Excel最常用的5个函数!会用最后一个才是高手

是不是在处理Excel数据时,面对繁琐的操作烦恼不已?手动操作不仅耗时费力,还容易出错。别担心,表姐这就为你揭秘Excel中几个超实用的函数,让数据处理变得轻松高效!表姐整理了552页《Office从...

新手必会的53个Excel函数_惊呆小伙伴的全套excel函数技能

(新手入门+进阶+新函数)一、新手入门级(24个)1、Sum函数:求和=Sum(区域)2、Average函数:求平均值=Average(区域)3、Count函数:数字个数=Count(区域)4、Cou...

打工人私藏的4个Excel函数秘籍,效率提升3.7%

小伙伴们好啊,今天咱们分享几个常用函数公式的典型应用。合并内容如下图,希望将B列的姓名,按照不同部门合并到一个单元格里。=TEXTJOIN(",",1,IF(A$2:A$15=D2,B...

Excel偷偷更新的8个函数!原来高手都在用这些隐藏技能

领导突然要销售数据,你手忙脚乱筛选到眼花...同事3分钟搞定的报表,你折腾半小时还在填充公式...明明用了VLOOKUP,却总显示#N/A错误...别慌!今天教你的8个动态数组函数,就像给Excel装...

Excel表格随机函数怎么用?讲解三种随机函数在不同场景的应用

excel随机函数,其特点是能够生成一组随机数字,根据不同需求,还能批量生成小数位和整数,及指定行数和列数,或指定区间范围内的数字。这里根据需求,作者设置了三个问题,第1个是随机生成0至1之间的数字...

单纯随机抽样该如何进行?_单纯随机抽样的适用范围及注意事项

在数据分析中,抽样是指从全部数据中选择部分数据进行分析,以发掘更大规模数据集中的有用信息。在收集数据过程中,绝大多数情况下,并不采取普查的方式获取总体中所有样本的数据信息,而是以各类抽样方法抽取其中若...

随机函数在Excel中的应用_随机函数在excel中的应用实例

【分享成果,随喜正能量】职场,如果你没有价值,那么你随时可能被取代;如果你的价值不如别人,那么社会也不会惯你,你将被无情地淘汰掉。不管什么时候,你一定要学会构建自己的价值。每个人都应该思考这个问题:我...