Python 多线程:伪多线程?详细代码总结

Python的单线程和多线程 python的单线程和多线程 阅读详情

1. 普通多线程

# 1. 主线程,子线程各单独执行,最终都正常结束

import threading
import time 

def doWaiting():
    print(f"start waiting: {time.strftime('%H:%M:%S')}")
    time.sleep(3)
    print(f"stop waiting: {time.strftime('%H:%M:%S')}")

t = threading.Thread(target = doWaiting)
          
t.start()           # 子线程

time.sleep(1)    
print("Start job")  # 主线程并不等子线程执行完毕
print("End job")

2. 主线程等子线程:join()

# 2. 主线程等待子线程(本质上将多线程变成了单线程)

import threading
import time 

def doWaiting():
    print(f"start waiting: {time.strftime('%H:%M:%S')}")
    time.sleep(3)
    print(f"stop waiting: {time.strftime('%H:%M:%S')}")

t = threading.Thread(target = doWaiting)
          
t.start()           # 子线程

time.sleep(1)    
print("Start job")  

t.join()            # 主线程等待子线程,直至执行完毕
          
print("End job")

3. 主线程带走子线程:setDaemon()

# 3. 主线程结束,则全部子线程被强制终止(子线程为守护线程)

import time
import threading

# 子线程
def sub_thread(num):
    time.sleep(1)
    print(f"thread {num} is running")

print(f"main_thread starting..")

time.sleep(1)
for i in range(3):
    t = threading.Thread(target=sub_thread, args=(i+1, ))
    t.setDaemon(True)   # 把子线程设置为守护线程,必须在start()之前设置
    t.start()
#     t.join()  # 可以使用 join()让主程序等子线程
print("main_thread endded!")

4. 共享全局变量

# 4. 多线程共享全局变量(线程不安全)

import threading, time 

def add_thread():
    global count
    
    for _ in range(10000000):  # 进行大数级别运算(普通运算可能没有看不出)
        count += 1 
    print(f"add_thread运算结束之后,count = {count}")
    
    time.sleep(0.5)
    print(f"add thread endded")

def sub_thread():
    global count

    for _ in range(10000000):  # 进行大数级别运算(普通运算可能没有看不出)
        count -= 1
    print(f"sub_thread运算结束之后,count = {count}")

    time.sleep(0.5)
    print(f"sub thread endded")

def main_thread():
    global count
    
    print(f"main thread starting...")
    
    t1 = threading.Thread(target=add_thread)
    t1.start() 
    t1.join()     # join是阻塞等线程执行完毕。
    
    t2 = threading.Thread(target=sub_thread)
    t2.start()
    t2.join()     # join是阻塞等线程执行完毕。

    count += 88
    
count = 100

start_time = time.time()
main_thread()
end_time = time.time()
print()
print(f"主线程执行完毕之后,count = {count}")
print("main thread finished!")
print(f"耗时:{round(end_time-start_time, 3)} s")


# 最终:主线程执行完毕之后,count 的结果是不固定的

# 注:如果使用 t.join() ,则将线程变为顺序执行(本质上多线程变成了单线程)
main thread starting...
add_thread运算结束之后,count = 10000100
add thread endded
sub_thread运算结束之后,count = 100
sub thread endded

主线程执行完毕之后,count = 188
main thread finished!
耗时:2.621 s

5. 互斥锁

# 5. 互斥锁

import threading, time 

def add_thread():
    global count
    
    lock.acquire()
    for _ in range(10000000):    # 进行大数级别运算(普通运算可能没有看不出)
        count += 1 
    print(f"add_thread运算结束之后,count = {count}")
    lock.release()
    
    time.sleep(0.5)
    print(f"add thread endded")

def sub_thread():
    global count
    
    lock.acquire()
    for _ in range(10000000):   # 进行大数级别运算(普通运算可能没有看不出)
        count -= 1
    print(f"sub_thread运算结束之后,count = {count}")
    lock.release()
    
    time.sleep(0.5)
    print(f"sub thread endded")

def main_thread():
    global count
    
    print(f"main thread starting...")
    
    t1 = threading.Thread(target=add_thread)
    t1.start() 
    
    t2 = threading.Thread(target=sub_thread)
    t2.start()

    lock.acquire()
    count += 88
    lock.release()
    
count = 100
lock = threading.Lock()

start_time = time.time()
main_thread()
end_time = time.time()
print()
print(f"主线程执行完毕之后,count = {count}")
print("main thread finished!")
print(f"耗时:{round(end_time-start_time, 3)} s")

# 最终:主线程执行完毕之后,count 的结果是188

# 注:可以使用 t.join() 来设置主线程等待子线程结束
main thread starting...
add_thread运算结束之后,count = 10000100
add thread endded
sub_thread运算结束之后,count = 100

主线程执行完毕之后,count = 188
main thread finished!
耗时:1.495 s
sub thread endded

6. 信号锁

# 6. 信号锁 Semaphore:许一定数量的线程同时更改数据

import  threading, time

def sub_thread(num, se):
    se.acquire()
    print(f"sub_thread {num} is running...")
    time.sleep(1)
    se.release()
    
# 设置允许 5 个线程同时运行
semaphore = threading.BoundedSemaphore(5)
def main_thread():
    for i in range(20):
        t = threading.Thread(target=sub_thread, args=(i+1, semaphore))
        t.start()
        
main_thread()

7. 事件锁

# 7. 事件线程锁 event:用于主线程控制其他线程的执行,事件是一个简单的线程同步对象
'''
主要提供以下的几个方法:
- clear将flag设置为 False
- set将flag设置为 True
- is_set判断是否设置了flag
- wait会一直监听flag,如果没有检测到flag就一直处于阻塞状态

事件处理的机制:
全局定义了一个Flag,当Flag的值为False,那么event.wait()就会阻塞,
当flag值为True,那么event.wait()便不再阻塞

import threading, time
from threading import Timer

event = threading.Event()

def lighter(waiting_time, lighting):
    if not event.is_set():
        if waiting_time >= 5:   # 即使开始的状态是 没有定义 flag,但是等待时间超过 5 s则可通过
            event.set()
            lighting = "Green"
            print("Go!")
        else:
            print("wait...")
            event.wait()       
    else:
        if lighting == "Green":  
            print("Go!")
        else:
            print("Stop!")
    

def car_control(waiting_time=0, flag=None):
    if flag == True:    
        event.set()
        lighting = "Green"
    else:
        event.clear()
        lighting = "Red"
        
    lighter(waiting_time, lighting)


# car_control(3)          # wait...
car_control(10)         # Go!
# car_control(0, True)    # Go!
# car_control()             # wait...

8. 全局解释器锁 GIL

# 8. GIL 全局解释器锁(Global Interpreter Lock)

'''
在非 python 环境中,单核情况下,同时只能有一个任务执行。多核时可以支持多个线程同时执行。
但是在 python 中,无论有多少个核同时只能执行一个线程。究其原因,这就是由于GIL的存在导致的。

GIL 是 Python 设计之初为了数据安全所做的决定。
Python 中的某个线程想要执行,必须先拿到 GIL。可以把GIL看作是执行任务的“通行证”,并且在一个Python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行。
GIL 只在 CPython解释器中才有,因为 CPython调用的是c语言的原生线程,不能直接操作cpu,只能利用GIL保证同一时间只能有一个线程拿到数据。
在 PyPy 和 JPython 中没有GIL。

虽然,在Python的不同解释器实现中,如PyPy就移除了GIL,其执行速度更快(不单单是去除GIL的原因)。
但是,我们通常使用的CPython解释器版本占有着统治地位的使用量
'''
'''
Python多线程的工作流程:

- 拿到公共数据
- 申请GIL
- Python解释器调用操作系统原生线程
- cpu执行运算
- 当该线程执行一段时间消耗完,无论任务是否已经执行完毕,都会释放GIL
- 下一个被CPU调度的线程重复上面的过程
'''
'''
Python针对不同类型的任务,多线程执行效率是不同的:

- 对于CPU密集型任务(各种循环处理、计算等等),由于计算工作多,ticks计数很快就会达到阈值,然后触发GIL的释放与再竞争(多个线程来回切换是需要消耗资源的),所以Python下的多线程对CPU密集型任务并不友好。

- IO密集型任务(文件处理、网络通信等涉及数据读写的操作),多线程能够有效提升效率(单线程下有IO操作会进行IO等待,造成不必要的时间浪费,而开启多线程能在线程A等待时,自动切换到线程B,可以不浪费CPU的资源,从而能提升程序执行效率)。所以Python的多线程对IO密集型任务比较友好。
'''
'''
在实际使用中的建议:
- Python中想要充分利用多核CPU,就用多进程。因为每个进程有各自独立的GIL,互不干扰,这样就可以真正意义上的并行执行。
- 在Python中,多进程的执行效率优于多线程(仅仅针对多核CPU而言)。同时建议在IO密集型任务中使用多线程,在计算密集型任务中使用多进程。
- 另外,深入研究Python的协程机制,你会有惊喜的。
'''

多进程方面更多参考:

  1. python 彻底解读多线程与多进程
  2. 一文看懂Python多进程与多线程编程(工作学习面试必读)

参考:

  1. 多线程threading——简单明了
  2. python多线程详解(超详细)
  3. ——简易理解为什么 Python 多线程是伪多线程
python:实现线程池(附完整源码) 阅读详情

相关推荐

C++常见面试题总结

C++常见面试题总结

xu_fu_yong的专栏 8万+

进程、线程、多线程相关总结

一、说说概念 1、进程(process) 狭义定义:进程就是一段程序的执行过程。 广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。 简单的来讲进程的概念主要有两点:第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、...

weixin_33807284的博客 291

5分钟搞定!用FunASR在本地快速部署达摩院Paraformer语音识别模型

本文提供了一份快速部署指南,教你如何在5分钟内利用FunASR工具包在本地电脑上启动达摩院Paraformer语音识别模型。Paraformer作为一款非自回归端到端模型,以其推理速度快、识别精度高的特点,结合FunASR的一键式模型加载和统一API,让开发者能轻松构建本地语音识别系统,极大降低了前沿AI技术的应用门槛。

q9w8e7r6t5的博客 605

Python多线程与线程池(python线程池ThreadPoolExecutor)concurrent.futures高级别异步执行封装

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

Dontla的博客 1万+

2023最新版kali安装教程

2023最新版kali安装教程 打开kali官网(https://www.kali.org/),下载kali镜像

qq_46346209的博客 2万+

解密微信视频号推荐算法的三大核心机制

本文深入解析微信视频号推荐算法的三大核心机制:用户行为数据、视频内容质量和社交关系链。通过详细的数据分析和实战测试,揭示算法如何根据完播率、互动深度、原创性检测和社交关系等因素决定内容推荐。帮助用户和创作者更好地理解并利用视频号算法,提升内容曝光和观看体验。

weixin_42573113的博客 1786

Python 伪多线程

Python的“伪多线程”--- GILPython 伪多线程GIL Python 伪多线程 Python热度很高,能干的事也很多。虽然CPython底层实现用的C,但它的速度还是快不起来!即使你用了多进程或多线程!!!究其原因之一,Python的多线程是“伪多线程“! GIL GIL 全局解释器锁(GIL)通常被视为Python在高端多处理器服务器机器上部署的障碍,因为多线程Python程序实际上只使用一个CPU,因为(几乎)所有Python代码都只能在持有GIL的情况下运行。 早在Python1.5时

a786018072的博客 1624

详细介绍:国产操作系统银行麒麟V10的下载和安装

银河麒麟是由。银河麒麟已经发展为银河麒麟服务器操作系统、桌面操作系统、嵌入式操作系统、麒麟云、操作系统增值产品为代表的产品线。为攻克中国软件核心技术“卡脖子”的短板,银河麒麟建设自主的开源供应链,发起中国首个开源桌面操作系统根社区openKylin,银河麒麟操作系统以openKylin等自主根社区为依托,发布最新版本。

lz17267861157的博客 1万+

python3 线程池源码解析_源码解读 TDengine 中线程池的实现

这篇文章中提到了 tsched 的源码可以一读,所以去阅读了一下,总共220来行。1. 阅读前工作通过上文了解到这段程序实现的是一个任务队列,同时带有线程池。这段程序是计算机操作系统里经典的consumer-producer (生产者-消费者)问题的实现。凡是学过操作系统这门课的,都应该知道这个问题,做过习题。在阅读源码之前可以先尝试用伪代码实现上述生产者-消费者问题。2. 如何阅读?了解清楚使用...

weixin_35483528的博客 275

告别配置烦恼!保姆级教程:在Windows 10/11上为QT5.14.2配置MSVC2017编译器(附VS2022组件避坑指南)

本文提供了一份详细的保姆级教程,指导如何在Windows 10/11上为QT5.14.2配置MSVC2017编译器,包括VS2022组件避坑指南。从环境准备到关键配置,再到调试工具验证和Qt Creator中的编译器设置,一步步解决常见问题,帮助开发者快速搭建稳定可靠的开发环境。

weixin_30615767的博客 502

MongoDB启动失败(service mongod start):Failed to unlink socket file /tmp/mongodb-27017.sock Unknown error

错误日志(/var/log/mongodb/mongo.log): 2019-09-16T06:00:00.251+0000 I CONTROL [main] ***** SERVER RESTARTED ***** 2019-09-16T06:00:00.253+0000 I CONTROL [main] Automatically disabling TLS 1.0, to force-e...

deantzzz的博客 1838

python伪多线程

python伪多线程 python为什么不能多线程; 怎么用python实现并行。 一、多线程、多进程、守护线程 1.1 进程 狭义定义:进程就是一段程序的执行过程。 广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。 第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack

daotian 565

2023华为od机试真题【恢复数字序列】C++

2023华为od机试真题【恢复数字序列】C++ 对于一个连续正整数组成的序列,可以将其拼接成一个字符串,再将字符串里的部分字符打乱顺序。如序列8 9 10 11 12,拼接成的字符串为89101112,打乱一部分字符后得到90811211,原来的正整数10就被拆成了0和1。现给定一个按如上规则得到的打乱字符的字符串,请将其还原成连续正整数序列,并输出序列中最小的数字. 输入描述

MISAYAONE的博客 5729

为什么老说python是伪多线程,怎么解决?

目录一、什么是多线程、多进程、守护线程1.1 进程1.2 程序1.3 线程1.4 多线程1.5 守护线程1.6 进程与线程的区别1.7 进程与线程的优缺点二、利用Python进行并行计算2.1、并行?伪并行?2.2 GIL2.2.1 GIL是什么2.3 如何解决?2.3.1 使用多进程三、Python中threading的使用注意事项3.1 Python多线程的默认情况3.2 设置守护线程3.3 ...

melon0014的博客 2万+

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

python 伪多线程_python伪多线程

广告关闭腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元!本文首发于本人博客,转载请注明出处 写在前面作者电脑有 4 个 cpu,因此使用 4 个线程测试是合理的本文使用的 cpython 版本为 3. 6.4 本文使用的 pypy 版本为 5.9. 0-beta0,兼容 python 3.5 语法本文使用的 jython 版本为 2. 7...

weixin_39634898的博客 547

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

98、Python并发编程:Python的伪多线程、GIL以及自由线程特性

本文简单介绍了GIL的存在,通过代码演示了Python中多线程不能真正并发的现象。最后试用了Python3.13中的自由线程模式,对比了移除GIL后的多线程和单线程的执行效率。

南宫理的日知录 2328

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

python 伪多线程_python 多线程

Python模块:threading00x1 多线程基础讲解_↑↑↑↑↑↑↑↑↑↑↑↑↑要使用多线程的函数可以实例化一个Thread对象,每个Thread对象代表着一个线程,可以通过start()方法,开始运行。t = threading.Thread(target=worker) #将worker函数实例化为Thread对象t.start() #实例化以后需要开始这个线程由于pytho...

weixin_39912566的博客 161

python伪多线程_python3对多线程处理

importthreadingimporttimedefT1_job():print('T1 start')for i in range(10):print('begin sleep 0.1s')time.sleep(0.1)print('T1 finish')defT2_job():print('T2 start')print('T2 finish')defmain():print('---ma...

weixin_40001309的博客 148

破局并发迷思:Java真多线程与Python伪多线程的本质对决及死锁防御战

特性Java (JVM)线程模型1:1 映射到内核线程用户级线程,受GIL全局管控并行能力真并行,可利用多核伪并行,同一时刻仅单核执行字节码适用场景CPU密集型、I/O密集型通吃仅适合I/O密集型;CPU密集需用多进程内存共享堆内存共享,需注意线程安全进程间内存隔离,线程间共享但受GIL保护基本类型上下文切换较重(内核态切换)较轻(但在GIL争抢下效率受限)Java与Python的多线程机制虽有一真一假之别,但在构建高并发系统时,对锁的敬畏之心是相通的。

2603_94941287的博客 390

Python 编程的多线程为何是伪多线程?

Python中的多线程没有真正实现多现程,也就是经常说的伪多线程!为什么这么说,我们了解一个概念,全局解释器锁(GIL)。Python代码的执行由Python虚拟机(解释器)来控制,Python在设计之初就考虑要在主循环中,同时只有一个线程在执行,就像单CPU的系统中运行多个进程那样,内存中可以存放多个程序,但任意时刻,只有一个程序在CPU中运行。同样地,虽然Python解释器可以运行多个线程,只有一个线程在解释器中运行。对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同时只有一个

墨子琦的博客 1061

python的伪多线程

你平时用的几乎肯定是 CPython(除非你特意去装了 Jython 或 IronPython)。你写的 Python 3 代码,绝大多数情况下都是在 CPython 上运行的。

shaohjz的博客 513

python为什么是伪多线程_python的假线程

广告关闭腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元!由于现在的操作系统上的进程越来越轻量,导致进程和线程之间的区别越来越少。 事实上,linux 并没有原生的线程,线程是通过进程实现的。 python 中每一个进程会启动一个解释器,而线程会共享一个解释器。 python 中的线程是通过标准库 threading 实现的。 而启动一个线...

weixin_39837607的博客 1160

python 伪多线程_从伪并行的 Python 多线程说起

写在前面作者电脑有 4 个 CPU,因此使用 4 个线程测试是合理的本文使用的 cpython 版本为 3.6.4本文使用的 pypy 版本为 5.9.0-beta0,兼容 Python 3.5 语法本文使用的 jython 版本为 2.7.0,兼容 Python 2.7 语法若无特殊说明,作语言解时,python 指 Python 语言;作解释器解时,python 指cpython本文使用的测速...

weixin_39943442的博客 262

python 彻底解读多线程与多进程_python 多进程与多线程浅析

python多线程是伪多线程,同时间最多只有一个线程在执行,但这样并不代码python的多线程没有作用,对于IO密集型的系统,python的多线程还是能极大的提升性能~关于python伪多线程可以去了解python GIL的概念。以下代码涉及python多线程,多进程,进程池相关操作:#encoding:utf-8from multiprocessing import Pool,Manager,c...

weixin_39634194的博客 136

python为什么是伪多线程_既然python的多线程是"伪多线程",那么多线程访问共享资源的时候,还需要线程锁吗...

最近处理的大多数任务都是基于python的多线程实现的,然而使用python逃避不开的一个话题就是,python的GIL(的全称是 Global Interpreter Lock)全局解释器锁是单线程的,那么是不是意味着python的多线程也是串行的?多线程对共享资源的使用就不需要锁(线程锁)了?笔者一开始也是这么误解:既然python解释器的锁是单线程的===》那么经过解释器生成的线程,是轮训执...

weixin_39663970的博客 178
上一篇: Python matplotlib 报错:RuntimeError: In set_size: Could not set the fontsize:弄清 figsize 和 dpi 的含义
下一篇: Numpy报错:ImportError: numpy.core.multiarray failed to import
Robin_Pi
博客等级 码龄9年 2万+粉丝 632原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值