python多线程之Threading
什么是线程?
线程是操作系统内核调度的基本单位,一个进程中包含一个或多个线程,同一个进程内的多个线程资源共享,线程相比进程是“轻”量级的任务,内核进行调度时效率更高。
多线程有什么优势?
多线程可以实现多任务并发执行,简化代码的编写难度,每一个独立的模块都可以设计成一个独立的线程运行
线程间通信比进程间通信难度更小,效率更高,因为资源共享
线程的调度比进程的调度效率高
Python 语言内置了多线程功能支持,而不是单纯地作为底层操作系统的调度方式,从而简化了 Python 的多线程编程
Threading库
多线程的启动方式(函数式和类对象式)
import threading
import time def runOne(info):
while True:
print(info)
time.sleep(1)
pass def runTwo(info):
while True:
print(info)
time.sleep(1)
pass if __name__ == '__main__':
t1 = threading.Thread(target = runOne, args = ("task one run",))
t2 = threading.Thread(target = runTwo, args = ("task two run",))
t1.start() # 启动t1
t2.start() # 启动t2
t1.join() # 主线程等待t1子线程结束(阻塞)
t2.join() # 主线程等待t2子线程结束(阻塞)
import threading
import time class MyThread(threading.Thread):
def __init__(self, info):
super(MyThread, self).__init__()
self.info = info def run(self):
while True:
print(self.info)
time.sleep(1)
pass if __name__ == "__main__":
t1 = MyThread("taskone")
t2 = MyThread("tasktwo")
t1.start() # 启动t1
t2.start() # 启动t2
t1.join() # 主线程等待t1子线程结束(阻塞)
t2.join() # 主线程等待t2子线程结束(阻塞)
守护线程
如果将任务1设置为任务2的守护线程,当任务2结束时,任务1也自动结束。上述例子中如果将子线程设置主线程的守护线程,那么当主线程结束时,子线程也自动结束。
import threading
import time class MyThread(threading.Thread):
def __init__(self, info):
super(MyThread, self).__init__()
self.info = info def run(self):
print(self.info)
time.sleep(1)
print(self.info)
time.sleep(1)
pass if __name__ == "__main__":
t1 = MyThread("taskone")
t1.setDaemon(True) # t1设置为主线程的守护线程
t1.start() # 启动t1
主线程等待子线程结束
为了实现子线程结束后,主线程再结束的目的,可以使用join方法,让主线程等待子线程执行。
import threading
import time class MyThread(threading.Thread):
def __init__(self, info):
super(MyThread, self).__init__()
self.info = info def run(self):
print(self.info)
time.sleep(1)
print(self.info)
time.sleep(1)
print("Sub tash end")
pass if __name__ == "__main__":
t1 = MyThread("taskone")
t1.start() # 启动t1
t1.join() # 主线程等待子线程结束
print("main task end")
多线程之间的通信
互斥锁
由于同一个进程下多个任务可以共享数据,因此都可以访问同一个全局变量,速度很快,但是也有问题。因为线程的调度是内核实现,线程自己不知道自己什么时候被切换,有可能是访问全局变量操作了一半(访问全局变量,看着是一句话,实际上是多条操作)然后被切换了,当下次得到调度时,此时全局变量有可能已经被其他线程修改了,导致再次访问时获取的数据不对,从而引发异常。解决的办法是在访问全局变量的时候,将全局变量锁住,让其它线程访问不了。互斥锁就是用来实现这个功能,加了互斥锁的地方,同一时间永远只有一个线程可以访问这个全局变量,直到该线程访问完毕后,其他任务才能访问。
import threading
import time num = 0
mutex = threading.Lock() class MyThread(threading.Thread):
def run(self):
global num
time.sleep(1) if mutex.acquire():
num = num + 1
msg = self.name + ' set num to ' + str(num)
print(msg)
mutex.release() def test():
for i in range(5):
t = MyThread()
t.start()
如果加了互斥锁,打印就是1 2 3 4 5;如果没加锁,打印就是乱序的。
消息队列
消息队列是一个线程将消息发送给另一个线程的方式,可以把消息列表理解成一个管道,一个线程在管道的一端放东西,一个线程在管道的另一端取东西,东西在管道内一个接一个的流动。通过发消息的方式就可以避免集中访问全局变量的问题,安全性更高。
import threading
import time
import queue q = queue.Queue() def runOne():
while True:
msg = q.get()
print(msg)
pass def runTwo():
while True:
q.put("message")
time.sleep(1)
pass if __name__ == '__main__':
t1 = threading.Thread(target = runOne)
t2 = threading.Thread(target = runTwo)
t1.start() # 启动t1
t2.start() # 启动t2
t1.join() # 主线程等待t1子线程结束(阻塞)
t2.join() # 主线程等待t2子线程结束(阻塞)
线程怎么结束?
由于threading模块没有提供停止线程的方法,也就是说线程start之后,就处于失控的状态,只能被动的等待它自己结束,这显然是问题。对于线程的结束,本文提供两种方法:第一种发下消息,让线程自己主动退出;第二种调动自定义接口直接结束线程。
import threading
import time
import queue q = queue.Queue() def runOne():
while True:
msg = q.get() if msg == 'exit':
break print(">> %s" % msg)
print("task one stop") def runTwo():
while True:
info = input()
q.put(info) if info == 'exit':
break
print("task two stop") if __name__ == '__main__':
t1 = threading.Thread(target = runOne)
t2 = threading.Thread(target = runTwo)
t1.start() # 启动t1
t2.start() # 启动t2
t1.join() # 主线程等待t1子线程结束(阻塞)
t2.join() # 主线程等待t2子线程结束(阻塞)
import inspect
import ctypes
import threading
import time def _async_raise(tid, exctype):
tid = ctypes.c_long(tid)
if not inspect.isclass(exctype):
exctype = type(exctype)
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
if res == 0:
raise ValueError("invalid thread id")
elif res != 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
raise SystemError("PyThreadState_SetAsyncExc failed") # 结束线程的函数
def stop_thread(thread):
_async_raise(thread.ident, SystemExit) def runOne(info):
while True:
print(info)
time.sleep(1)
pass def runTwo(info):
while True:
print(info)
time.sleep(1)
pass if __name__ == '__main__':
t1 = threading.Thread(target = runOne, args = ("task one run",))
t2 = threading.Thread(target = runTwo, args = ("task two run",))
t1.start()
t2.start() time.sleep(5)
stop_thread(t1) # 停止t1任务 print('------------------------') time.sleep(5)
stop_thread(t2) # 停止t1任务 t1.join()
t2.join()
GIL(Global Interpreter Lock)全局解释器锁
在非python环境中,单核情况下同时只能有一个任务执行;多核情况下可以支持多个线程同时执行。但是在python中,无论有多少核,同时只能执行一个线程。究其原因,是由于GIL的存在导致的。GIL的全称是Global Interpreter Lock(全局解释器锁),来源是python设计之初的考虑,为了数据安全而设计。某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行。GIL只在cpython中才有,因为cpython调用的是c语言的原生线程,所以他不能直接操作cpu,只能利用GIL保证同一时间只能有一个线程拿到数据。使用建议:针对多核CPU场景,多进程的执行效率优于多线程,优先使用多进程。
python多线程之Threading的更多相关文章
- “死锁” 与 python多线程之threading模块下的锁机制
一:死锁 在死锁之前需要先了解的概念是“可抢占资源”与“不可抢占资源”[此处的资源可以是硬件设备也可以是一组信息],因为死锁是与不可抢占资源有关的. 可抢占资源:可以从拥有他的进程中抢占而不会发生副作 ...
- python多线程之threading模块
threading模块中的对象 其中除了Thread对象以外,还有许多跟同步相关的对象 threading模块支持守护线程的机制 Thread对象 直接调用法 import threading imp ...
- python多线程之threading、ThreadPoolExecutor.map
背景: 某个应用场景需要从数据库中取出几十万的数据时,需要对每个数据进行相应的操作.逐个数据处理过慢,于是考虑对数据进行分段线程处理: 方法一:使用threading模块 代码: # -*- codi ...
- python 线程之 threading(四)
python 线程之 threading(三) http://www.cnblogs.com/someoneHan/p/6213100.html中对Event做了简单的介绍. 但是如果线程打算一遍一遍 ...
- python 线程之 threading(三)
python 线程之 threading(一)http://www.cnblogs.com/someoneHan/p/6204640.html python 线程之 threading(二)http: ...
- python并发编程之threading线程(一)
进程是系统进行资源分配最小单元,线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.进程在执行过程中拥有独立的内存单元,而多个线程共享内存等资源. 系列文章 py ...
- python多线程之Condition(条件变量)
#!/usr/bin/env python # -*- coding: utf-8 -*- from threading import Thread, Condition import time it ...
- python多线程之semaphore(信号量)
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import time import random semaphore = ...
- python 线程之threading(五)
在学习了Event和Condition两个线程同步工具之后还有一个我认为比较鸡肋的工具 semaphores 1. 使用semaphores的使用效果和Condition的notify方法的效果基本相 ...
随机推荐
- 【Spring注解驱动开发】如何使用@Bean注解指定初始化和销毁的方法?看这一篇就够了!!
写在前面 在[String注解驱动开发专题]中,前面的文章我们主要讲了有关于如何向Spring容器中注册bean的知识,大家可以到[String注解驱动开发专题]中系统学习.接下来,我们继续肝Spri ...
- CCNA-Part1:网络基础概念
由于身处一家网络公司,日常项目中设计到的网络概念较多,恰逢之后公司组织相关培训.借此机会,打算写下一系列文章用于之后梳理并回顾.文章主要涉及 NA,NP 中所覆盖的知识.由于网络分为较多方向,如路由交 ...
- .Net Core 中GC的工作原理
前言 .NET 中GC管理你服务的内存分配和释放,GC是运行公共语言运行时(CLR Common Language Runtime)中,GC可以帮助开发人员有效的分配内存和和释放内存,大多数情况下是不 ...
- JavaWeb网上图书商城完整项目-CommonUtils(1生成uuid,2Map转换成JavaBean)
java工程中添加上面的jar包 CommonUtils类就两个方法: l String uuid():生成长度32的随机字符,通常用来做实体类的ID.底层使用了UUID类完成: l T toBe ...
- C#数据结构与算法系列(十九):选择排序算法(SelectSort)
1.介绍 选择排序算法属于内部排序算法,是从欲排序的数据中,按指定的规则选出某一元素,再依规定交换位置达到排序的目的 时间复杂度:O(n^2) 双层for 2.思想 选择排序(select sorti ...
- python文件处理-将图像根据坐标切割成若干小图
代码涉及到:遍历目标路径,选取csv后缀的文件,遍历csv每一行,读取坐标,用cv操作图片 # !/usr/bin/python # -*- coding: UTF- -*- import panda ...
- 【vue】---- ElementUI 实现上传Excel
1.功能描述:vue 项目使用 el-upload 实现上传 Excel. 2.功能效果:在el-upload基础上做了样式整改. 3.功能实现: // el-upload 上传组件 <temp ...
- 猿灯塔:最详细Dubbo相关面试题!
1.Dubbo是什么? Dubbo是阿里巴巴开源的基于 Java 的高性能 RPC 分布式服务框架,现已成为 Apache 基金会孵化项目. 面试官问你如果这个都不清楚,那下面的就没必要问了. 官网: ...
- css兼容大部分浏览器的文本超出部分显示省略号
css之字体多行省略(兼容大部分浏览器) 字体单行显示省略号 <style> .box1{ width: 500px; height: 1.5em; overflow: hidden; t ...
- Tomcat 架构原理解析到架构设计借鉴
Tomcat 发展这么多年,已经比较成熟稳定.在如今『追新求快』的时代,Tomcat 作为 Java Web 开发必备的工具似乎变成了『熟悉的陌生人』,难道说如今就没有必要深入学习它了么?学习它我们又 ...