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. [转]c++使用thread类时编译出错,对‘pthread_create’未定义的引用

    转载地址:https://blog.csdn.net/wuhui20091515/article/details/52531202 例子1 #include <iostream> #inc ...

  2. 推荐一款好用的免费远程控制软件——ToDesk

    创作立场声明:我在本文中评测的软件为自用,感觉不错并且全免费,第一时间发出来和大家分享,欢迎理性观点交流碰撞. 疫情刚开始的时候,待在家里不能上班,但是还是有很多工作需要在线完成,常常需要跑回办公室拿 ...

  3. docket 缺陷

    docker轻量级的虚拟机 依赖于内存和核数 相比于正常的虚拟机来说运行速度会慢

  4. Linux下安装mysql-5.7.28详细步骤

    一.下载Mysql 下载地址:https://downloads.mysql.com/archives/community/ 二.环境配置 检测系统是否自带Mysql # rmp -qa|grep m ...

  5. 解决使用Redis时配置 fastjson反序列化报错 com.alibaba.fastjson.JSONException: autoType is not support

    1.问题描述 在使用redis时,配置自定义序列化redisTemplate为FastJsonRedisSerializer .  1 /** 2 * 自定义redis序列化器 3 */ 4 @Sup ...

  6. Django的视图层和模板层

    目录 一.视图层 1. 小白必会三板斧 2. JsonResponse 3. FBV与CBV 3.1 FVB 3.2 CBV 4. CBV的源码 5. 给CBV加装饰器 二.模板层 1. 模板语法 2 ...

  7. 01.从0实现一个JVM语言之架构总览

    00.一个JVM语言的诞生过程 文章集合以及项目展望 源码github地址 这一篇将是架构总览, 将自顶向下地叙述自制编译器的要素; 文章目录 01.从0实现一个JVM语言之架构总览 架构总览目前完成 ...

  8. 49元起!魅族Lipro LED灯泡发布:无可视频闪、无积热问题

    转: 49元起!魅族Lipro LED灯泡发布:无可视频闪.无积热问题 魅族智能家居品牌Lipro今日办会,公布一批新品,均面向健康照明领域打造. 魅族强调,Lipro健康照明产品主打博物馆级健康光. ...

  9. 2020年12月-第02阶段-前端基础-CSS字体样式

    CSS字体样式属性调试工具 应用 使用css字体样式完成对字体的设置 使用css外观属性给页面元素添加样式 1.font字体 1.1 font-size:大小 作用: font-size属性用于设置字 ...

  10. threejs 基础概要

    threejs 基础概要 点击查看官方文档 下面是翻译的内容(稍作修改) 先了解一下Three.js应用程序的结构.Three.js应用程序需要创建一堆对象并将它们连接在一起.下图表示一个小three ...