Python 多线程(一)
Python多线程(一)
线程
一个进程中的各个线程与主线程共享同一片数据空间,因此相对于进程,线程间的信息共享与通讯更加便捷。线程以并发方式执行,得益于这种并行与数据共享的机制,使得多任务协作的实现更加简单。
Python线程模型
Python代码的执行是由Python虚拟机控制。在 CPython 中,由于存在 全局解释器锁(GIL),同一时刻只有一个线程可以执行。这种限制使得python的多线程这像在单CPU上跑多进程,只能做到并发,无法做到并行。 。
Python虚拟机按照下面所述方式来切换线程
切换线程被放在一个互斥锁中
设置GIL
执行某个线程A
执行下面操作之一
- 执行一定数量的A的python代码(字节码指令)
- 线程主动让出控制权
将A的执行状态保存,以备下次执行
解锁GIL
某些 Python I/O 例程(调用了内置的操作系统 C 代码的那种),GIL 会在 I/O 调用前被释放,以允许其他线程在 I/O 执行的时候运行。而对于那些没有太多 I/O 操作的代码而言,更倾向于在该线程整个时间片内始终占有处理器(和 GIL)。总而言之,I/O 密集型的 Python 程序要比计算密集型的代码能够更好地利用多线程环境。
如果想利用多核心计算机的计算资源,推荐使用 multiprocessing
或 concurrent.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()方法默认将args和kwargs传入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 多线程(一)的更多相关文章
- python多线程学习记录
1.多线程的创建 import threading t = t.theading.Thread(target, args--) t.SetDeamon(True)//设置为守护进程 t.start() ...
- python多线程编程
Python多线程编程中常用方法: 1.join()方法:如果一个线程或者在函数执行的过程中调用另一个线程,并且希望待其完成操作后才能执行,那么在调用线程的时就可以使用被调线程的join方法join( ...
- Python 多线程教程:并发与并行
转载于: https://my.oschina.net/leejun2005/blog/398826 在批评Python的讨论中,常常说起Python多线程是多么的难用.还有人对 global int ...
- python多线程
python多线程有两种用法,一种是在函数中使用,一种是放在类中使用 1.在函数中使用 定义空的线程列表 threads=[] 创建线程 t=threading.Thread(target=函数名,a ...
- python 多线程就这么简单(转)
多线程和多进程是什么自行google补脑 对于python 多线程的理解,我花了很长时间,搜索的大部份文章都不够通俗易懂.所以,这里力图用简单的例子,让你对多线程有个初步的认识. 单线程 在好些年前的 ...
- python 多线程就这么简单(续)
之前讲了多线程的一篇博客,感觉讲的意犹未尽,其实,多线程非常有意思.因为我们在使用电脑的过程中无时无刻都在多进程和多线程.我们可以接着之前的例子继续讲.请先看我的上一篇博客. python 多线程就这 ...
- python多线程监控指定目录
import win32file import tempfile import threading import win32con import os dirs=["C:\\WINDOWS\ ...
- python多线程ssh爆破
python多线程ssh爆破 Python 0x01.About 爆弱口令时候写的一个python小脚本,主要功能是实现使用字典多线程爆破ssh,支持ip表导入,字典数据导入. 主要使用到的是pyth ...
- 【python,threading】python多线程
使用多线程的方式 1. 函数式:使用threading模块threading.Thread(e.g target name parameters) import time,threading def ...
- <转>Python 多线程的单cpu与cpu上的多线程的区别
你对Python 多线程有所了解的话.那么你对python 多线程在单cpu意义上的多线程与多cpu上的多线程有着本质的区别,如果你对Python 多线程的相关知识想有更多的了解,你就可以浏览我们的文 ...
随机推荐
- 使用 Tye 辅助开发 k8s 应用竟如此简单(三)
续上篇,这篇我们来进一步探索 Tye 更多的使用方法.本篇我们来了解一下如何在 Tye 中如何对数据库进行链接. Newbe.Claptrap 是一个用于轻松应对并发问题的分布式开发框架.如果您是首次 ...
- django学习-23.admin管理后台的数据表数据的自定义展示
目录结构 1.前言 2.自定义设置一张指定的数据表的列表展示内容 2.1.第一步:如果我们想让数据表[hello_person]里面的表字段值全部展示出来,需在应用[hello]里的[admin.py ...
- SSL (Secure Sockets Layer)
本文转载自SSL (Secure Sockets Layer) TLS简介 The Transport Layer Security (TLS) protocol aims primarily to ...
- 详解SSH 框架中对象调用流程
摘要:SSH=Struts+Spring+Hibernate SSH不是一个框架,而是多个框架(struts+spring+hibernate)的集成,是目前较流行的一种Web应用程序开源集成框架,用 ...
- vue高级
1.nrm nrm提供了一些最常用的npm包镜像地址,可以快速切换服务器地址下载资源.它只是提供了地址,并不是装包工具.如果没有安装npm,需要安装node,然后直接安装即可.node下载链接:htt ...
- Glibc堆管理机制基础
最近正在学习linux下堆的管理机制,收集了书籍和网络上的资料,以自己的理解做了整理,做个记录.如果有什么不对的地方欢迎指出! Memory Allocator 常见的内存管理机制 dlmalloc: ...
- 基于μcOS-II实时操作系统源码实现RMS和EDF调度(共享资源)
μcOS-II多任务实验报告(RMS.EDF调度) 目录 μcOS-II多任务实验报告(RMS.EDF调度) 一.实验概述 二.环境搭建 三.代码分析 四.实验步骤 1 给TCB块添加扩展 2 创建并 ...
- Django的ORM封装接口详细
[前言]Django的orm操作本质上会根据对接的数据库引擎,翻译成对应的sql语句:所有使用Django开发的项目无需关心程序底层使用的是MySQL.Oracle.sqlite....,如果数据库迁 ...
- 分布式文件系统FastDFS简介、搭建、与SpringBoot整合实现图片上传
之前大学时搭建过一个FastDFS的图片服务器,当时只是抱着好奇的态度搭着玩一下,当时搭建采用了一台虚拟机,tracker和storage服务在一台机器上放着,最近翻之前的博客突然想着在两台机器上搭建 ...
- 【DP】斜率优化初步
向y总学习了斜率优化,写下这篇blog加深一下理解. 模板题:https://www.acwing.com/problem/content/303/ 分析 因为本篇的重点在于斜率优化,故在此给出状态转 ...