Python多线程(一)

线程

​ 一个进程中的各个线程与主线程共享同一片数据空间,因此相对于进程,线程间的信息共享与通讯更加便捷。线程以并发方式执行,得益于这种并行与数据共享的机制,使得多任务协作的实现更加简单。

Python线程模型

​ Python代码的执行是由Python虚拟机控制。在 CPython 中,由于存在 全局解释器锁(GIL),同一时刻只有一个线程可以执行。这种限制使得python的多线程这像在单CPU上跑多进程,只能做到并发,无法做到并行。 。

Python虚拟机按照下面所述方式来切换线程

切换线程被放在一个互斥锁中

  1. 设置GIL

  2. 执行某个线程A

  3. 执行下面操作之一

    1. 执行一定数量的A的python代码(字节码指令)
    2. 线程主动让出控制权
  4. A的执行状态保存,以备下次执行

  5. 解锁GIL

​ 某些 Python I/O 例程(调用了内置的操作系统 C 代码的那种),GIL 会在 I/O 调用前被释放,以允许其他线程在 I/O 执行的时候运行。而对于那些没有太多 I/O 操作的代码而言,更倾向于在该线程整个时间片内始终占有处理器(和 GIL)。总而言之,I/O 密集型的 Python 程序要比计算密集型的代码能够更好地利用多线程环境。

​ 如果想利用多核心计算机的计算资源,推荐使用 multiprocessingconcurrent.futures.ProcessPoolExecutor

Threading模块

未引进线程

def func(name, t):
print(name, "开始", int(time()))
sleep(t)
print(name, "结束", int(time())) print("程序开始执行")
start = time()
func("猪", 4)
func("牛", 4)
end = time()
print("总共运行:",int( end - start))

结果

程序开始执行
猪 开始 1618821733
猪 结束 1618821737
牛 开始 1618821737
牛 结束 1618821741
总共运行: 8

引入线程

方式一:创建Thread实例,传给它一个函数

  • 通过给Thread类构造函数的关键字参数func来定义这个线程将要运行哪个函数,通过args参数来传递func的参数。注意args是一个元组,如果func只需要一个参数时应该这样传参args=(arg1,)。关键字only参数通过kwargs来传入。kwargs是一个字典。
from threading import Thread
from time import sleep, time def func(name, t):
print(name, "开始", int(time()))
sleep(t)
print(name, "结束", int(time())) T1 = Thread(target=func,args=('猪',4))
T2 = Thread(target=func,args=('牛',4)) print("主线程开始执行")
start = time()
T1.start() #线程开始执行
T2.start() #线程开始执行
end = time()
print("主线程共运行:",int( end - start))

结果

主线程开始执行
猪 开始 1618822143
牛 开始 1618822143
主线程共运行: 0
猪 结束 1618822147
牛 结束 1618822147

解释

当调用thread实例T的start()方法时,这时会创建一个独立的线程,在这个线程中运行实例T的run()方法.run()方法默认argskwargs传入target.具体来说就是将 ( '猪' , 4) 传入 func.

当T1.start() T2.start() 调用时,会分别创建两个独立的线程,加上主线程一共有三个独立线程在python虚拟机中运行。三个独立线程以不可预测的进度运行。因此有了上面的运行结果。

注意到,当主线程结束后,整个程序并没有结束。python解释器等到所有的非守护线程结束之后才结束整个程序。这是threading类带来的福利。这也是我们使用threading模块,而不使用更底层的thread模块(这里说的不是Thread类。)的一个原因。

方式二:继承Thread,并重新定义run方法

刚才解释过,调用实例T的start()方法时,会在一个独立的线程中运行实例的run() 方法。run的默认行为是,用构造函数中的target和kwargs来运行target。因此我们可以在子类中重新定义了run方法,在run方法中写出我们想要并发执行的功能。

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

from threading import Thread
from time import sleep, time def func(name, t):
print(name, "开始", int(time()))
sleep(t)
print(name, "结束", int(time())) class MyThread(Thread):
def __init__(self,target,args=(), kwargs={}):
Thread.__init__(self)
#如果子类型重载了构造函数,它一定要确保在做任何事前,先发起调用基类构造器(Thread.__init__())。
self.target = target
self.args = args
self.kwargs = kwargs def run(self):
self.target(*self.args,**(self.kwargs)) print("程序开始执行")
start = time() T1 = MyThread(func,('猪',4))
T2 = MyThread(func,('牛',4))
T1.start()
T2.start() end = time()
print("总共运行:",int( end - start))

结果

程序开始执行
猪 开始 1618824594
牛 开始 1618824594
总共运行: 0
猪 结束 1618824598
牛 结束 1618824598

全局解释器锁GIL

CPython 解释器所采用的一种机制,它确保同一时刻只有一个线程在执行 Python bytecode。此机制通过设置对象模型(包括 dict 等重要内置类型)针对并发访问的隐式安全简化了 CPython 实现。给整个解释器加锁使得解释器多线程运行更方便,其代价则是牺牲了在多处理器上的并行性。

不过,某些标准库或第三方库的扩展模块被设计为在执行计算密集型任务如压缩或哈希时释放 GIL。此外,在执行 I/O 操作时也总是会释放 GIL。

创建一个(以更精细粒度来锁定共享数据的)“自由线程”解释器的努力从未获得成功,因为这会牺牲在普通单处理器情况下的性能。据信克服这种性能问题的措施将导致实现变得更复杂,从而更难以维护

Python 多线程(一)的更多相关文章

  1. python多线程学习记录

    1.多线程的创建 import threading t = t.theading.Thread(target, args--) t.SetDeamon(True)//设置为守护进程 t.start() ...

  2. python多线程编程

    Python多线程编程中常用方法: 1.join()方法:如果一个线程或者在函数执行的过程中调用另一个线程,并且希望待其完成操作后才能执行,那么在调用线程的时就可以使用被调线程的join方法join( ...

  3. Python 多线程教程:并发与并行

    转载于: https://my.oschina.net/leejun2005/blog/398826 在批评Python的讨论中,常常说起Python多线程是多么的难用.还有人对 global int ...

  4. python多线程

    python多线程有两种用法,一种是在函数中使用,一种是放在类中使用 1.在函数中使用 定义空的线程列表 threads=[] 创建线程 t=threading.Thread(target=函数名,a ...

  5. python 多线程就这么简单(转)

    多线程和多进程是什么自行google补脑 对于python 多线程的理解,我花了很长时间,搜索的大部份文章都不够通俗易懂.所以,这里力图用简单的例子,让你对多线程有个初步的认识. 单线程 在好些年前的 ...

  6. python 多线程就这么简单(续)

    之前讲了多线程的一篇博客,感觉讲的意犹未尽,其实,多线程非常有意思.因为我们在使用电脑的过程中无时无刻都在多进程和多线程.我们可以接着之前的例子继续讲.请先看我的上一篇博客. python 多线程就这 ...

  7. python多线程监控指定目录

    import win32file import tempfile import threading import win32con import os dirs=["C:\\WINDOWS\ ...

  8. python多线程ssh爆破

    python多线程ssh爆破 Python 0x01.About 爆弱口令时候写的一个python小脚本,主要功能是实现使用字典多线程爆破ssh,支持ip表导入,字典数据导入. 主要使用到的是pyth ...

  9. 【python,threading】python多线程

    使用多线程的方式 1.  函数式:使用threading模块threading.Thread(e.g target name parameters) import time,threading def ...

  10. <转>Python 多线程的单cpu与cpu上的多线程的区别

    你对Python 多线程有所了解的话.那么你对python 多线程在单cpu意义上的多线程与多cpu上的多线程有着本质的区别,如果你对Python 多线程的相关知识想有更多的了解,你就可以浏览我们的文 ...

随机推荐

  1. SSL/TLS协议详解(下)——TLS握手协议

    本文转载自SSL/TLS协议详解(下)--TLS握手协议 导语 在博客系列的第2部分中,对证书颁发机构进行了深入的讨论.在这篇文章中,将会探索整个SSL/TLS握手过程,在此之前,先简述下最后这块内容 ...

  2. 链接服务器sql语句

     EXEC  sp_addlinkedserver      @server='sha',--被访问的服务器别名       @srvproduct='',      @provider='SQLOL ...

  3. 运行maven遇到的坑,差点崩溃了。

    参考链接1:https://blog.csdn.net/lch_cn/article/details/8225448/ 参考链接2:https://jingyan.baidu.com/article/ ...

  4. oracle 查锁

    reference:https://www.cnblogs.com/XQiu/p/5212787.html--以下几个为相关表SELECT * FROM v$lock;SELECT * FROM v$ ...

  5. 分布式流转开发常见报错FAQ

    鸿蒙入门指南,小白速来!0基础学习路线分享,高效学习方法,重点答疑解惑--->[课程入口] HarmonyOS开发中分布式协同是非常重要的一个功能,大家在刚接触的时候可能会出现各种各样的错误.我 ...

  6. MySQL:字段约束与索引

    字段约束 MySQL的字段约束共四种: 约束名 关键字 描述 主键约束 PRIMARY KEY 字段值唯一,且不能为NULL 非空约束 NOT NULL 字段值不能为NULL 唯一约束 UNIQUE ...

  7. XXL-JOB v2.3.0 发布 | 易用性增强

    转: XXL-JOB v2.3.0 发布 | 易用性增强 v2.3.0 Release Notes 1.[新增]调度过期策略:调度中心错过调度时间的补偿处理策略,包括:忽略.立即补偿触发一次等: 2. ...

  8. 单细胞分析实录(9): 展示marker基因的4种图形(二)

    在上一篇中,我已经讲解了展示marker基因的前两种图形,分别是tsne/umap图.热图,感兴趣的读者可以回顾一下.这一节我们继续学习堆叠小提琴图和气泡图. 3. 堆叠小提琴图展示marker基因 ...

  9. 分形、分形几何、数据可视化、Python绘图

    本系列采用turtle.matplotlib.numpy这三个Python工具,以分形与计算机图像处理的经典算法为实例,通过程序和图像,来帮助读者一步步掌握Python绘图和数据可视化的方法和技巧,并 ...

  10. MyBatis(九):MyBatis类型处理器(TypeHandler)详解

    TypeHandler简介 TypeHandler,顾名思义类型转换器,就是将数据库中的类型与Java中的类型进行相互转换的处理器. MyBatis 在设置预处理语句(PreparedStatemen ...