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 多线程的相关知识想有更多的了解,你就可以浏览我们的文 ...
随机推荐
- JMM内存模型相关笔记整理
JMM 内存模型是围绕并发编程中原子性.可见性.有序性三个特征来建立的 原子性:就是说一个操作不能被打断,要么执行完要么不执行,类似事务操作,Java 基本类型数据的访问大都是原子操作,long 和 ...
- 教你玩转CSS Position(定位)
CSS Position(定位) position 属性指定了元素的定位类型. position 属性的五个值: static relative fixed absolute sticky 元素可以使 ...
- Navicat Premium的数据传输功能----将远程Mysql数据库复制到本地数据库的方法
1.先连上本地.远程的数据库 2.在本地建一个和你要复制的远程数据库的名称一样的数据库 3.数据转移.工具-->数据传输-->填写源数据库和目标数据库-->下一步-->开始 注 ...
- Python数据读取函数
1.读取mat数据 import scipy.io as sio data_mat = sio.loadmat(data.mat) 官方文档 获取的数据为字典型,其中"data"为 ...
- 配置Nginx的坑及思路
我配置的是Django + uwsgi + Nginx 说下思路,先进行模块化测试: Django: Django 下 第一个坑是sql版本低问题,原因用pip安装不正确,在网上查了下按这个文章重装下 ...
- 分布式文件系统FastDFS简介、搭建、与SpringBoot整合实现图片上传
之前大学时搭建过一个FastDFS的图片服务器,当时只是抱着好奇的态度搭着玩一下,当时搭建采用了一台虚拟机,tracker和storage服务在一台机器上放着,最近翻之前的博客突然想着在两台机器上搭建 ...
- 关于Laravel框架中Guard的底层实现
1. 什么是Guard 在Laravel/Lumen框架中,用户的登录/注册的认证基本都已经封装好了,开箱即用.而登录/注册认证的核心就是: 用户的注册信息存入数据库(登记) 从数据库中读取数据和用户 ...
- 《深入浅出WPF》-刘铁猛学习笔记——XAML
XAML是什么? XAML是微软公司创造的一种开发语言,XAML的全称是 Extensible Application Markup Language,即可拓展应用程序标记语言. 它由XML拓展而来, ...
- js浅拷贝(地址引用)和深拷贝(克隆)
浅拷贝和深拷贝相对于引用类型而言的. js有两大类型值类型(基本数据类型)和引用类型(object,function,array): 值类型保存在栈上,引用类型保存在堆上. 浅拷贝只是单纯的拷贝对象的 ...
- AI换脸
AI换脸 技术 调用到百度的AI接口,layui的图片上传,栅格化布局 核心代码 纯py文件运行 # encoding:utf-8 import requests import base64 impo ...