1.过程这个概念
过程,有时候被称作轻量级进程(LightweightProcess,LWP),是程序执行流的最低控制模块。统一标准的过程由过程ID,现阶段命令表针(PC),存储器结合和局部变量构成。此外,过程是过程里的一个实体线,被系统软件多带带生产调度和分配的基本要素,过程自己并不有着服务器资源。
2.threading.thread()简单地应用
2.1加上过程能是程序执行迅速
pythod的thread模块还是比较最底层的控制模块,pythod的threading模块是对thread做了很多包装,能够方便快捷被应用。
有一点在运行时不可缺少的网络资源,但是它能与同为1个进度的其他线程共享过程所具有的所有网络资源。
import threading import time def saySorry(): print("亲爱的,我错了,我能吃饭了吗?") time.sleep(5) if __name__=="__main__": start_time1=time.time() for i in range(5): t=threading.Thread(target=saySorry) t.start()#启动线程,即让线程开始执行 end_time1=time.time() print(end_time1-start_time1) start_time2=time.time() for i in range(5): t=saySorry() end_time2=time.time() print(end_time2-start_time2)
输出为:
亲爱的,我错了,我能吃饭了吗?
亲爱的,我错了,我能吃饭了吗?
亲爱的,我错了,我能吃饭了吗?
亲爱的,我错了,我能吃饭了吗?
亲爱的,我错了,我能吃饭了吗?
0.001995086669921875
亲爱的,我错了,我能吃饭了吗?
亲爱的,我错了,我能吃饭了吗?
亲爱的,我错了,我能吃饭了吗?
亲爱的,我错了,我能吃饭了吗?
亲爱的,我错了,我能吃饭了吗?
25.001766204833984
2.2主线程会等待所有的子线程结束后才结束
import threading from time import sleep,ctime def sing(): for i in range(3): print("正在唱歌...%d"%i) sleep(1) def dance(): for i in range(3): print("正在跳舞...%d"%i) sleep(1) if __name__=='__main__': print('---开始---:%s'%ctime()) t1=threading.Thread(target=sing) t2=threading.Thread(target=dance) t1.start() t2.start() #sleep(5)#屏蔽此行代码,试试看,程序是否会立马结束? print('---结束---:%s'%ctime())
输出为:
---开始---:Mon Sep 28 14:42:09 2020
正在唱歌...0
正在跳舞...0---结束---:Mon Sep 28 14:42:09 2020
正在唱歌...1
正在跳舞...1
正在唱歌...2
正在跳舞...2
如果释放‘sleep(5)’,输出为:
---开始---:Mon Sep 28 14:43:36 2020
正在唱歌...0
正在跳舞...0
正在跳舞...1
正在唱歌...1
正在唱歌...2正在跳舞...2
---结束---:Mon Sep 28 14:43:41 2020
3.查看线程数量
import threading from time import sleep,ctime def sing(): for i in range(3): print("正在唱歌...%d"%i) sleep(1) def dance(): for i in range(3): print("正在跳舞...%d"%i) sleep(1) if __name__=='__main__': print('---开始---:%s'%ctime()) t1=threading.Thread(target=sing) t2=threading.Thread(target=dance) t1.start() t2.start() while True: length=len(threading.enumerate()) print('当前运行的线程数为:%d'%length) if length<=1: break sleep(0.5)
输出为:
---开始---:Mon Sep 28 14:46:16 2020
正在唱歌...0
正在跳舞...0
当前运行的线程数为:3
当前运行的线程数为:3
正在唱歌...1
正在跳舞...1当前运行的线程数为:3
当前运行的线程数为:3
正在唱歌...2
正在跳舞...2
当前运行的线程数为:3
当前运行的线程数为:3
当前运行的线程数为:1
4.线程参数及顺序
4.1传递参数的方法
使用args传递参数threading.Thread(target=sing,args=(10,100,100))
使用kwargs传递参数threading.Thread(target=sing,kwargs={“a”:10,“b”:100,“c”:100})
同时使用args和kwargs传递参数threading.Thread(target=sing,args=(10,),kwargs={“b”:100,“c”:100})
4.2线程的执行顺序
import threading import time def sing(): for i in range(5): print("我是sing") time.sleep(1) def dance(): for i in range(5): print("我是dance") time.sleep(1) if __name__=='__main__': #创建两个子线程 t1=threading.Thread(target=sing) t2=threading.Thread(target=dance) #启动子线程 t1.start() t2.start()
输出为:
我是sing
我是dance
我是sing
我是dance
我是dance
我是sing
我是dance我是sing
我是sing
我是dance
说明:
从代码和执行结果我们可以看出,多线程程序的执行顺序是不确定的。当执行到sleep语句时,线程将被阻塞(Blocked),到sleep结束后,线程进入就绪(Runnable)状态,等待调度。而线程调度将自行选择一个线程执行。上面的代码中只能保证每个线程都运行完整个run函数,但是线程的启动顺序、run函数中每次循环的执行顺序都不能确定。
5.守护线程
守护线程:如果在程序中将子线程设置为守护线程,则该子线程会在主线程结束时自动退出,设置方式为thread.setDaemon(True),要在thread.start()之前设置,默认是false的,也就是主线程结束时,子线程依然在执行。
5.1如下代码,主线程已经exit()【其实并没有真正结束】,子线程还在继续执行
import threading import time def test(): for i in range(7): print("test is run:",i) time.sleep(1) if __name__=='__main__': #创建子线程 t1=threading.Thread(target=test) #启动子线程 t1.start() #休眠2秒 time.sleep(2) print("我OVER了") #退出 exit()
输出为:
test is run:0
test is run:1
我OVER了
test is run:2
test is run:3
test is run:4
test is run:5
test is run:6
5.2设置守护线程
为线程设置守护,如果主线程结束,子线程也随之结束。
import threading import time def test(): for i in range(7): print("test is run:",i) time.sleep(1) if __name__=='__main__': #创建子线程 t1=threading.Thread(target=test) #设置线程保护 t1.setDaemon(True) #启动子线程 t1.start() #休眠2秒 time.sleep(2) print("我OVER了") #退出 exit() 输出为: test is run:0 test is run:1 我OVER了 参考代码 import threading from threading import Lock,Thread import time,os '''
python多线程详解
什么是线程?
线程也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际运作单位。
线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所
拥有的全部资源。一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行
'''
'''
为什么要使用多线程?
线程在程序中是独立的、并发的执行流。与分隔的进程相比,进程中线程之间的隔离程度要小,它们共享内存、文件句柄
和其他进程应有的状态。
因为线程的划分尺度小于进程,使得多线程程序的并发性高。进程在执行过程之中拥有独立的内存单元,而多个线程共享
内存,从而极大的提升了程序的运行效率。
线程比进程具有更高的性能,这是由于同一个进程中的线程都有共性,多个线程共享一个进程的虚拟空间。线程的共享环境
包括进程代码段、进程的共有数据等,利用这些共享的数据,线程之间很容易实现通信。
操作系统在创建进程时,必须为改进程分配独立的内存空间,并分配大量的相关资源,但创建线程则简单得多。因此,使用多线程
来实现并发比使用多进程的性能高得要多。
'''
'''
总结起来,使用多线程编程具有如下几个优点:
进程之间不能共享内存,但线程之间共享内存非常容易。
操作系统在创建进程时,需要为该进程重新分配系统资源,但创建线程的代价则小得多。因此使用多线程来实现多任务并发执行比使用多进程的效率高
python语言内置了多线程功能支持,而不是单纯地作为底层操作系统的调度方式,从而简化了python的多线程编程。
''' ''' 普通创建方式 ''' #def run(n): #print('task',n) #time.sleep(1) #print('2s') #time.sleep(1) #print('1s') #time.sleep(1) #print('0s') #time.sleep(1) # #if __name__=='__main__': #t1=threading.Thread(target=run,args=('t1',))#target是要执行的函数名(不是函数),args是函数对应的参数,以元组的形式存在 #t2=threading.Thread(target=run,args=('t2',)) #t1.start() #t2.start() ''' 自定义线程:继承threading.Thread来定义线程类,其本质是重构Thread类中的run方法 ''' #class MyThread(threading.Thread): #def __init__(self,n): #super(MyThread,self).__init__()#重构run函数必须写 #self.n=n # #def run(self): #print('task',self.n) #time.sleep(1) #print('2s') #time.sleep(1) #print('1s') #time.sleep(1) #print('0s') #time.sleep(1) # #if __name__=='__main__': #t1=MyThread('t1') #t2=MyThread('t2') #t1.start() #t2.start() '''
守护线程
下面这个例子,这里使用setDaemon(True)把所有的子线程都变成了主线程的守护线程,
因此当主线程结束后,子线程也会随之结束,所以当主线程结束后,整个程序就退出了。
所谓'线程守护',就是主线程不管该线程的执行情况,只要是其他子线程结束且主线程执行完毕,主线程都会关闭。也就是说:主线程不等待该守护线程的执行完再去关闭。
''' #def run(n): #print('task',n) #time.sleep(1) #print('3s') #time.sleep(1) #print('2s') #time.sleep(1) #print('1s') # #if __name__=='__main__': #t=threading.Thread(target=run,args=('t1',)) #t.setDaemon(True) #t.start() #print('end') ''' 通过执行结果可以看出,设置守护线程之后,当主线程结束时,子线程也将立即结束,不再执行 ''' ''' 主线程等待子线程结束 为了让守护线程执行结束之后,主线程再结束,我们可以使用join方法,让主线程等待子线程执行 ''' #def run(n): #print('task',n) #time.sleep(2) #print('5s') #time.sleep(2) #print('3s') #time.sleep(2) #print('1s') #if __name__=='__main__': #t=threading.Thread(target=run,args=('t1',)) #t.setDaemon(True)#把子线程设置为守护线程,必须在start()之前设置 #t.start() #t.join()#设置主线程等待子线程结束 #print('end') ''' 多线程共享全局变量 线程时进程的执行单元,进程时系统分配资源的最小执行单位,所以在同一个进程中的多线程是共享资源的 ''' #g_num=100 #def work1(): #global g_num #for i in range(3): #g_num+=1 #print('in work1 g_num is:%d'%g_num) # #def work2(): #global g_num #print('in work2 g_num is:%d'%g_num) # #if __name__=='__main__': #t1=threading.Thread(target=work1) #t1.start() #time.sleep(1) #t2=threading.Thread(target=work2) #t2.start() ''' 由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据, 所以出现了线程锁,即同一时刻允许一个线程执行操作。线程锁用于锁定资源,可以定义多个锁,像下面的代码,当需要独占 某一个资源时,任何一个锁都可以锁定这个资源,就好比你用不同的锁都可以把这个相同的门锁住一样。 由于线程之间是进行随机调度的,如果有多个线程同时操作一个对象,如果没有很好地保护该对象,会造成程序结果的不可预期, 我们因此也称为“线程不安全”。 为了防止上面情况的发生,就出现了互斥锁(Lock) ''' #def work(): #global n #lock.acquire() #temp=n #time.sleep(0.1) #n=temp-1 #lock.release() # # #if __name__=='__main__': #lock=Lock() #n=100 #l=[] #for i in range(100): #p=Thread(target=work) #l.append(p) #p.start() #for p in l: #p.join() ''' 递归锁:RLcok类的用法和Lock类一模一样,但它支持嵌套,在多个锁没有释放的时候一般会使用RLock类 ''' #def func(lock): #global gl_num #lock.acquire() #gl_num+=1 #time.sleep(1) #print(gl_num) #lock.release() # # #if __name__=='__main__': #gl_num=0 #lock=threading.RLock() #for i in range(10): #t=threading.Thread(target=func,args=(lock,)) #t.start() ''' 信号量(BoundedSemaphore类) 互斥锁同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据,比如厕所有3个坑, 那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去 ''' #def run(n,semaphore): #semaphore.acquire()#加锁 #time.sleep(3) #print('run the thread:%sn'%n) #semaphore.release()#释放 # # #if __name__=='__main__': #num=0 #semaphore=threading.BoundedSemaphore(5)#最多允许5个线程同时运行 #for i in range(22): #t=threading.Thread(target=run,args=('t-%s'%i,semaphore)) #t.start() #while threading.active_count()!=1: #pass #else: #print('----------all threads done-----------') ''' python线程的事件用于主线程控制其他线程的执行,事件是一个简单的线程同步对象,其主要提供以下的几个方法: clear将flag设置为False set将flag设置为True is_set判断是否设置了flag wait会一直监听flag,如果没有检测到flag就一直处于阻塞状态 事件处理的机制:全局定义了一个Flag,当Flag的值为False,那么event.wait()就会阻塞,当flag值为True, 那么event.wait()便不再阻塞 ''' event=threading.Event() def lighter(): count=0 event.set()#初始者为绿灯 while True: if 5<count<=10: event.clear()#红灯,清除标志位 print("33[41;lmred light is on...33[0m]") elif count>10: event.set()#绿灯,设置标志位 count=0 else: print('33[42;lmgreen light is on...33[0m') time.sleep(1) count+=1 def car(name): while True: if event.is_set():#判断是否设置了标志位 print('[%s]running.....'%name) time.sleep(1) else: print('[%s]sees red light,waiting...'%name) event.wait() print('[%s]green light is on,start going...'%name) #startTime=time.time() light=threading.Thread(target=lighter,) light.start() car=threading.Thread(target=car,args=('MINT',)) car.start() endTime=time.time() #print('用时:',endTime-startTime) '''
GIL全局解释器
在非python环境中,单核情况下,同时只能有一个任务执行。多核时可以支持多个线程同时执行。但是在python中,无论有多少个核
同时只能执行一个线程。究其原因,这就是由于GIL的存在导致的。
GIL的全程是全局解释器,来源是python设计之初的考虑,为了数据安全所做的决定。某个线程想要执行,必须先拿到GIL,我们可以
把GIL看做是“通行证”,并且在一个python进程之中,GIL只有一个。拿不到线程的通行证,并且在一个python进程中,GIL只有一个,
拿不到通行证的线程,就不允许进入CPU执行。GIL只在cpython中才有,因为cpython调用的是c语言的原生线程,所以他不能直接操
作cpu,而只能利用GIL保证同一时间只能有一个线程拿到数据。而在pypy和jpython中是没有GIL的
python在使用多线程的时候,调用的是c语言的原生过程。
'''
'''
python针对不同类型的代码执行效率也是不同的
1、CPU密集型代码(各种循环处理、计算等),在这种情况下,由于计算工作多,ticks技术很快就会达到阀值,然后出发GIL的
释放与再竞争(多个线程来回切换当然是需要消耗资源的),所以python下的多线程对CPU密集型代码并不友好。
2、IO密集型代码(文件处理、网络爬虫等设计文件读写操作),多线程能够有效提升效率(单线程下有IO操作会进行IO等待,
造成不必要的时间浪费,而开启多线程能在线程A等待时,自动切换到线程B,可以不浪费CPU的资源,从而能提升程序的执行
效率)。所以python的多线程对IO密集型代码比较友好。
'''
'''
主要要看任务的类型,我们把任务分为I/O密集型和计算密集型,而多线程在切换中又分为I/O切换和时间切换。如果任务属于是I/O密集型,
若不采用多线程,我们在进行I/O操作时,势必要等待前面一个I/O任务完成后面的I/O任务才能进行,在这个等待的过程中,CPU处于等待
状态,这时如果采用多线程的话,刚好可以切换到进行另一个I/O任务。这样就刚好可以充分利用CPU避免CPU处于闲置状态,提高效率。但是
如果多线程任务都是计算型,CPU会一直在进行工作,直到一定的时间后采取多线程时间切换的方式进行切换线程,此时CPU一直处于工作状态,
此种情况下并不能提高性能,相反在切换多线程任务时,可能还会造成时间和资源的浪费,导致效能下降。这就是造成上面两种多线程结果不能的解释。
结论:I/O密集型任务,建议采取多线程,还可以采用多进程+协程的方式(例如:爬虫多采用多线程处理爬取的数据);对于计算密集型任务,python此时就不适用了。
'''
综上所述,这篇文章就给大家介绍到这里了,希望可以给大家带来帮助。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/128697.html
本文给大家介绍一类从视频里获取视频帧的办法,因为单核获取视频帧速率比较慢,因而接下来我们增强了线程同步的办法,感兴趣的朋友能够出手试一试 Python迅速获取视频帧(线程同步) 现在详细介绍一下一类从视频里获取视频帧的办法,因为单核获取视频帧速率比较慢,因而接下来我们增强了线程同步的办法。 1、获取视频帧 获取视频帧关键用了Opencv控制模块。 在其中: camera=cv2.V...
摘要:中关于线程的标准库是,之前在版本中的在之后更名为,无论是还是都应该尽量避免使用较为底层的而应该使用。而与线程相比,协程尤其是结合事件循环无论在编程模型还是语法上,看起来都是非常友好的单线程同步过程。 项目地址:https://git.io/pytips 要说到线程(Thread)与协程(Coroutine)似乎总是需要从并行(Parallelism)与并发(Concurrency)谈起...
摘要:进程可创建多个线程来执行同一程序的不同部分。就绪等待线程调度。运行线程正常运行阻塞暂停运行,解除阻塞后进入状态重新等待调度。消亡线程方法执行完毕返回或者异常终止。多线程多的情况下,依次执行各线程的方法,前头一个结束了才能执行后面一个。 浅谈Python多线程 作者简介: 姓名:黄志成(小黄)博客: 博客 线程 一.什么是线程? 操作系统原理相关的书,基本都会提到一句很经典的话: 进程...
摘要:多线程的理解多进程和多线程都可以执行多个任务,线程是进程的一部分。多线程创建在中,同样可以实现多线程,有两个标准模块和,不过我们主要使用更高级的模块。多线程的应用场景。 1、多线程的理解 多进程和多线程都可以执行多个任务,线程是进程的一部分。线程的特点是线程之间可以共享内存和变量,资源消耗少(不过在Unix环境中,多进程和多线程资源调度消耗差距不明显,Unix调度较快),缺点是线程之间...
摘要:多线程和锁作者博客进程和线程进程是执行中的计算机程序。线程包括开始执行顺序和结束三部分。的多进程相关模块模块是高级别的多线程模块。线程锁当多线程争夺锁时,允许第一个获得锁的线程进入临街区,并执行代码。 Python 多线程和锁 作者博客:http://zzir.cn/ 进程和线程 进程是执行中的计算机程序。每个进程都拥有自己的地址空间、内存、数据栈及其它的辅助数据。操作系统管理着所有的...
阅读 874·2023-01-14 11:38
阅读 820·2023-01-14 11:04
阅读 672·2023-01-14 10:48
阅读 1830·2023-01-14 10:34
阅读 880·2023-01-14 10:24
阅读 740·2023-01-14 10:18
阅读 469·2023-01-14 10:09
阅读 507·2023-01-14 10:02