多线程库-threading 多线程lru
bigegpt 2024-12-19 11:31 5 浏览
1.threading简介
threading库是python的线程模型,利用threading库我们可以轻松实现多线程任务。
2.进程与线程简介
通过上图,我们可以直观的总结出进程、线程及其之间的关系与特点:
- 进程是资源分配的最小单元,一个程序至少包含一个进程
- 线程是程序执行的最小单元,一个进程至少包含一个线程
- 每个进程都有自己独占的地址空间、内存、数据栈等;由于进程间的资源独立,所以进程间通信(IPC)是多进程的关键问题
- 同一进程下的所有线程都共享该进程的独占资源,由于线程间的资源共享,所有数据同步与互斥是多线程的难点
此外,多进程多线程也必须考虑硬件资源的架构:
- 单核CPU中每个进程中同时刻只能运行一个线程,只在多核CPU中才能够实现线程并发
- 当线程需运行但运行空间不足时,先运行高优先级线程,后运行低优先级线程
- Windows系统新开进行会增加很大的开销,因此Windows系统下使用多线程更具优势,这时更应该考虑的问题是资源同步和互斥
- Linux系统新开进程的开销增加很小,因此Linux系统下使用多进程更具优势,这时更应该考虑的问题是进程间通信
3.python多线程特点
python的多线程并非真正意义上的多线程,由于全局解释器锁(GIL)的存在,python中的线程只有在获得GIL后才拥有运行权限,而GIL同一时刻只能被一个线程所拥有。
python在运行计算密集型的多线程程序时,更倾向于让线程在整个时间片内始终占据GIL,而I/O密集型的多线程程序在I/O被调用前会释放GIL,允许其他线程在I/O执行时获得GIL,因此python的多线程更适用于I/O密集型的程序(网络爬虫)。
4.threading实现多线程
线程创建
守护线程是指在程序运行时在后台提供一种通用服务的线程,比如垃圾回收线程;这种线程在程序中并非不可或缺。
默认创建的线程为非守护线程,等所有的非守护线程结束后,程序也就终止了,同时杀死进程中的所有守护线程。
只要非守护线程还在运行,程序就不会终止。
import threading
import time
#将创建的函数传递进threading.Thread()对象
def func():
print(threading.current_thread().getName())
t1 = threading.Thread(target=func,name='test_threading_1')
t1.start()
t1.join()
#继承threading.Thread类,改写run()方法
class TestThread(threading.Thread):
def __init__(self,name):
super(TestThread,self).__init__()
self.name = name
def run(self):
print(f'线程{self.name}正在进行!')
n = 0
while n < 5:
n += 1
print(f'线程{self.name}>>>{n}')
time.sleep(1)
print(f'线程{self.name}结束运行')
t1 = TestThread('thread-1')
t2 = TestThread('thread-2')
t1.start()
t2.start()
锁对象:threading.Lock
锁被用来实现对共享资源的同步访问;通过为每一个共享资源创建一个Lock对象,我们需要访问该资源时只能通过条用acquire方法来获取锁对象,待资源访问结束后,调用release方法释放Lock对象。
from threading import Thread,Lock
import time
lock = Lock()
def func():
global n
#加锁
lock.acquire()
team = n
time.sleep(1)
n = team-1
#释放锁
lock.release()
if __name__ == '__main__':
n = 100
l = []
for i in range(100):
t = Thread(target=func)
l.append(t)
t.start()
for t in l:
#将t线程设置成阻塞状态,直到t线程执行完后才能进入下一线程
t.join()
print(n)
from threading import Thread,Lock
x = 0
lock = Lock()
def func():
global x
lock.acquire()
for i in range(6000):
x = x+1
lock.release()
if __name__ == '__main__':
t1 = Thread(target=func)
t2 = Thread(target=func)
t3 = Thread(target=func)
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
print(x)
递归锁对象:threading.RLock
在应用锁对象时,会发生死锁;死锁是指两个或两个以上的线程在执行过程中,因争夺资源访问权而造成的互相等待的现象,从而一直僵持下去。
递归锁对象就是用来解决死锁问题的,RLock对象内部维护着一个Lock和一个counter变量,counter记录着acquire的次数,从而使得资源可以被多次acquire,直到一个线程的所有acquire都被release时,其他线程才能够acquire资源。
from threading import Thread,RLock,currentThread
import time
rlock1 = rlock2 = RLock()
class Test(Thread):
def run(self):
self.task1()
self.task2()
def task1(self):
rlock1.acquire()
print(f'{self.name}获得锁1')
rlock2.acquire()
print(f'{self.name}获得锁2')
rlock2.release()
print(f'{self.name}释放锁2')
rlock1.release()
print(f'{self.name}释放锁1')
def task2(self):
rlock2.acquire()
print(f'{self.name}获得锁2')
time.sleep(1)
rlock1.acquire()
print(f'{self.name}获得锁1')
rlock1.release()
print(f'{self.name}释放锁1')
rlock2.release()
print(f'{self.name}释放锁2')
for i in range(3):
t = Test()
t.start()
条件变量对象:threading.Condition
import threading
import time
condition_lock = threading.Condition()
PRE = 0
def pre():
print(PRE)
return PRE
def test_thread_hi():
condition_lock.acquire()
print('wait for the commend of test_thread_hello')
condition_lock.wait_for(pre)
print('contain doing')
condition_lock.release()
def test_thread_hello():
time.sleep(1)
condition_lock.acquire()
global PRE
PRE = 1
print('change PRE to 1')
print('tell the test_thread_hi to acquire lock')
condition_lock.notify()
condition_lock.release()
print('you need lock?')
def main():
thread_hi = threading.Thread(target=test_thread_hi)
thread_hello = threading.Thread(target=test_thread_hello)
thread_hi.start()
thread_hello.start()
if __name__ == '__main__':
main()
信息量对象:threading.Semaphore
一个信号量管理一个内部计数器,acquire( )方法会减少计数器,release( )方法则增加计算器,计数器的值永远不会小于零,当调用acquire( )时,如果发现该计数器为零,则阻塞线程,直到调用release( ) 方法使计数器增加。
import threading
import time
semaphore4 = threading.Semaphore(4)
def thread_semaphore(index):
semaphore4.acquire()
time.sleep(2)
print('thread_%s is runing'%index)
semaphore4.release()
def main():
for index in range(9):
threading.Thread(target=thread_semaphore,args=(index,)).start()
if __name__ == '__main__':
main()
事件对象:threading.Event
如果一个或多个线程需要知道另一个线程的某个状态才能进入下一步的操作,就可以使用线程的event事件对象来处理。
import threading
import time
event = threading.Event()
def student_exam(student_id):
print('学生%s等监考老师发卷'%student_id)
event.wait()
print('开始考试了')
def invigilate_teacher():
time.sleep(3)
print('考试时间到了,学生们可以考试了')
event.set()
def main():
for student_id in range(5):
threading.Thread(target=student_exam,args=(student_id,)).start()
threading.Thread(target=invigilate_teacher).start()
if __name__ == '__main__':
main()
定时器对象:threading.Timer
表示一个操作需要在等待一段时间之后执行,相当于一个定时器。
栅栏对象:threading.Barrier
1.threading简介
threading库是python的线程模型,利用threading库我们可以轻松实现多线程任务。
2.进程与线程简介
通过上图,我们可以直观的总结出进程、线程及其之间的关系与特点:
- 进程是资源分配的最小单元,一个程序至少包含一个进程
- 线程是程序执行的最小单元,一个进程至少包含一个线程
- 每个进程都有自己独占的地址空间、内存、数据栈等;由于进程间的资源独立,所以进程间通信(IPC)是多进程的关键问题
- 同一进程下的所有线程都共享该进程的独占资源,由于线程间的资源共享,所有数据同步与互斥是多线程的难点
此外,多进程多线程也必须考虑硬件资源的架构:
- 单核CPU中每个进程中同时刻只能运行一个线程,只在多核CPU中才能够实现线程并发
- 当线程需运行但运行空间不足时,先运行高优先级线程,后运行低优先级线程
- Windows系统新开进行会增加很大的开销,因此Windows系统下使用多线程更具优势,这时更应该考虑的问题是资源同步和互斥
- Linux系统新开进程的开销增加很小,因此Linux系统下使用多进程更具优势,这时更应该考虑的问题是进程间通信
3.python多线程特点
python的多线程并非真正意义上的多线程,由于全局解释器锁(GIL)的存在,python中的线程只有在获得GIL后才拥有运行权限,而GIL同一时刻只能被一个线程所拥有。
python在运行计算密集型的多线程程序时,更倾向于让线程在整个时间片内始终占据GIL,而I/O密集型的多线程程序在I/O被调用前会释放GIL,允许其他线程在I/O执行时获得GIL,因此python的多线程更适用于I/O密集型的程序(网络爬虫)。
4.threading实现多线程
线程创建
守护线程是指在程序运行时在后台提供一种通用服务的线程,比如垃圾回收线程;这种线程在程序中并非不可或缺。
默认创建的线程为非守护线程,等所有的非守护线程结束后,程序也就终止了,同时杀死进程中的所有守护线程。
只要非守护线程还在运行,程序就不会终止。
import threading
import time
#将创建的函数传递进threading.Thread()对象
def func():
print(threading.current_thread().getName())
t1 = threading.Thread(target=func,name='test_threading_1')
t1.start()
t1.join()
#继承threading.Thread类,改写run()方法
class TestThread(threading.Thread):
def __init__(self,name):
super(TestThread,self).__init__()
self.name = name
def run(self):
print(f'线程{self.name}正在进行!')
n = 0
while n < 5:
n += 1
print(f'线程{self.name}>>>{n}')
time.sleep(1)
print(f'线程{self.name}结束运行')
t1 = TestThread('thread-1')
t2 = TestThread('thread-2')
t1.start()
t2.start()
锁对象:threading.Lock
锁被用来实现对共享资源的同步访问;通过为每一个共享资源创建一个Lock对象,我们需要访问该资源时只能通过条用acquire方法来获取锁对象,待资源访问结束后,调用release方法释放Lock对象。
from threading import Thread,Lock
import time
lock = Lock()
def func():
global n
#加锁
lock.acquire()
team = n
time.sleep(1)
n = team-1
#释放锁
lock.release()
if __name__ == '__main__':
n = 100
l = []
for i in range(100):
t = Thread(target=func)
l.append(t)
t.start()
for t in l:
#将t线程设置成阻塞状态,直到t线程执行完后才能进入下一线程
t.join()
print(n)
from threading import Thread,Lock
x = 0
lock = Lock()
def func():
global x
lock.acquire()
for i in range(6000):
x = x+1
lock.release()
if __name__ == '__main__':
t1 = Thread(target=func)
t2 = Thread(target=func)
t3 = Thread(target=func)
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
print(x)
递归锁对象:threading.RLock
在应用锁对象时,会发生死锁;死锁是指两个或两个以上的线程在执行过程中,因争夺资源访问权而造成的互相等待的现象,从而一直僵持下去。
递归锁对象就是用来解决死锁问题的,RLock对象内部维护着一个Lock和一个counter变量,counter记录着acquire的次数,从而使得资源可以被多次acquire,直到一个线程的所有acquire都被release时,其他线程才能够acquire资源。
from threading import Thread,RLock,currentThread
import time
rlock1 = rlock2 = RLock()
class Test(Thread):
def run(self):
self.task1()
self.task2()
def task1(self):
rlock1.acquire()
print(f'{self.name}获得锁1')
rlock2.acquire()
print(f'{self.name}获得锁2')
rlock2.release()
print(f'{self.name}释放锁2')
rlock1.release()
print(f'{self.name}释放锁1')
def task2(self):
rlock2.acquire()
print(f'{self.name}获得锁2')
time.sleep(1)
rlock1.acquire()
print(f'{self.name}获得锁1')
rlock1.release()
print(f'{self.name}释放锁1')
rlock2.release()
print(f'{self.name}释放锁2')
for i in range(3):
t = Test()
t.start()
条件变量对象:threading.Condition
import threading
import time
condition_lock = threading.Condition()
PRE = 0
def pre():
print(PRE)
return PRE
def test_thread_hi():
condition_lock.acquire()
print('wait for the commend of test_thread_hello')
condition_lock.wait_for(pre)
print('contain doing')
condition_lock.release()
def test_thread_hello():
time.sleep(1)
condition_lock.acquire()
global PRE
PRE = 1
print('change PRE to 1')
print('tell the test_thread_hi to acquire lock')
condition_lock.notify()
condition_lock.release()
print('you need lock?')
def main():
thread_hi = threading.Thread(target=test_thread_hi)
thread_hello = threading.Thread(target=test_thread_hello)
thread_hi.start()
thread_hello.start()
if __name__ == '__main__':
main()
信息量对象:threading.Semaphore
一个信号量管理一个内部计数器,acquire( )方法会减少计数器,release( )方法则增加计算器,计数器的值永远不会小于零,当调用acquire( )时,如果发现该计数器为零,则阻塞线程,直到调用release( ) 方法使计数器增加。
import threading
import time
semaphore4 = threading.Semaphore(4)
def thread_semaphore(index):
semaphore4.acquire()
time.sleep(2)
print('thread_%s is runing'%index)
semaphore4.release()
def main():
for index in range(9):
threading.Thread(target=thread_semaphore,args=(index,)).start()
if __name__ == '__main__':
main()
事件对象:threading.Event
如果一个或多个线程需要知道另一个线程的某个状态才能进入下一步的操作,就可以使用线程的event事件对象来处理。
import threading
import time
event = threading.Event()
def student_exam(student_id):
print('学生%s等监考老师发卷'%student_id)
event.wait()
print('开始考试了')
def invigilate_teacher():
time.sleep(3)
print('考试时间到了,学生们可以考试了')
event.set()
def main():
for student_id in range(5):
threading.Thread(target=student_exam,args=(student_id,)).start()
threading.Thread(target=invigilate_teacher).start()
if __name__ == '__main__':
main()
定时器对象:threading.Timer
表示一个操作需要在等待一段时间之后执行,相当于一个定时器。
栅栏对象:threading.Barrier
编辑于 2021-11-03 09:20
相关推荐
- 了解Linux目录,那你就了解了一半的Linux系统
-
大到公司或者社群再小到个人要利用Linux来开发产品的人实在是多如牛毛,每个人都用自己的标准来配置文件或者设置目录,那么未来的Linux则就是一团乱麻,也对管理造成许多麻烦。后来,就有所谓的FHS(F...
- Linux命令,这些操作要注意!(linux命令?)
-
刚玩Linux的人总觉得自己在演黑客电影,直到手滑输错命令把公司服务器删库,这才发现命令行根本不是随便乱用的,而是“生死簿”。今天直接上干货,告诉你哪些命令用好了封神!喜欢的一键三连,谢谢观众老爷!!...
- Linux 命令速查手册:这 30 个高频指令,拯救 90% 的运维小白!
-
在Linux系统的世界里,命令行是强大的武器。对于运维小白而言,掌握一些高频使用的Linux命令,能极大提升工作效率,轻松应对各种系统管理任务。今天,就为大家奉上精心整理的30个Linu...
- linux必学的60个命令(linux必学的20个命令)
-
以下是Linux必学的20个基础命令:1.cd:切换目录2.ls:列出文件和目录3.mkdir:创建目录4.rm:删除文件或目录5.cp:复制文件或目录6.mv:移动/重命名文件或目录7....
- 提高工作效率的--Linux常用命令,能够决解95%以上的问题
-
点击上方关注,第一时间接受干货转发,点赞,收藏,不如一次关注评论区第一条注意查看回复:Linux命令获取linux常用命令大全pdf+Linux命令行大全pdf为什么要学习Linux命令?1、因为Li...
- 15 个实用 Linux 命令(linux命令用法及举例)
-
Linux命令行是系统管理员、开发者和技术爱好者的强大工具。掌握实用命令不仅能提高效率,还能解锁Linux系统的无限潜力,本文将深入介绍15个实用Linux命令。ls-列出目录内容l...
- Linux 常用命令集合(linux常用命令全集)
-
系统信息arch显示机器的处理器架构(1)uname-m显示机器的处理器架构(2)uname-r显示正在使用的内核版本dmidecode-q显示硬件系统部件-(SMBIOS/DM...
- Linux的常用命令就是记不住,怎么办?
-
1.帮助命令1.1help命令#语法格式:命令--help#作用:查看某个命令的帮助信息#示例:#ls--help查看ls命令的帮助信息#netst...
- Linux常用文件操作命令(linux常用文件操作命令有哪些)
-
ls命令在Linux维护工作中,经常使用ls这个命令,这是最基本的命令,来写几条常用的ls命令。先来查看一下使用的ls版本#ls--versionls(GNUcoreutils)8.4...
- Linux 常用命令(linux常用命令)
-
日志排查类操作命令查看日志cat/var/log/messages、tail-fxxx.log搜索关键词grep"error"xxx.log多条件过滤`grep-E...
- 简单粗暴收藏版:Linux常用命令大汇总
-
号主:老杨丨11年资深网络工程师,更多网工提升干货,请关注公众号:网络工程师俱乐部下午好,我的网工朋友在Linux系统中,命令行界面(CLI)是管理员和开发人员最常用的工具之一。通过命令行,用户可...
- 「Linux」linux常用基本命令(linux常用基本命令和用法)
-
Linux中许多常用命令是必须掌握的,这里将我学linux入门时学的一些常用的基本命令分享给大家一下,希望可以帮助你们。总结送免费学习资料(包含视频、技术学习路线图谱、文档等)1、显示日期的指令:d...
- Linux的常用命令就是记不住,怎么办?于是推出了这套教程
-
1.帮助命令1.1help命令#语法格式:命令--help#作用:查看某个命令的帮助信息#示例:#ls--help查看ls命令的帮助信息#netst...
- Linux的30个常用命令汇总,运维大神必掌握技能!
-
以下是Linux系统中最常用的30个命令,精简版覆盖日常操作核心需求,适合快速掌握:一、文件/目录操作1.`ls`-列出目录内容`ls-l`(详细信息)|`ls-a`(显示隐藏文件)...
- Linux/Unix 系统中非常常用的命令
-
Linux/Unix系统中非常常用的命令,它们是进行文件操作、文本处理、权限管理等任务的基础。下面是对这些命令的简要说明:**文件操作类:*****`ls`(list):**列出目录内容,显...
- 一周热门
- 最近发表
- 标签列表
-
- mybatiscollection (79)
- mqtt服务器 (88)
- keyerror (78)
- c#map (65)
- resize函数 (64)
- xftp6 (83)
- bt搜索 (75)
- c#var (76)
- mybatis大于等于 (64)
- xcode-select (66)
- mysql授权 (74)
- 下载测试 (70)
- linuxlink (65)
- pythonwget (67)
- androidinclude (65)
- logstashinput (65)
- hadoop端口 (65)
- vue阻止冒泡 (67)
- oracle时间戳转换日期 (64)
- jquery跨域 (68)
- php写入文件 (73)
- kafkatools (66)
- mysql导出数据库 (66)
- jquery鼠标移入移出 (71)
- 取小数点后两位的函数 (73)