志在指尖
用双手敲打未来

python多线程(python多线程实例详解)

python多线程

多线程和多进程是什么自行google补脑
对于python多线程的理解,我花了很长时刻,查找的大部份文章都不行通俗易懂。所以,这里力求用简略的比如,让你对多线程有个初步的认识。
单线程
在好些年前的MS-DOS年代,操作系统处理问题都是单任务的,我想做听音乐和看电影两件事儿,那么必定要先排一下次序。
(好吧!咱们不纠结在DOS年代是否有听音乐和看影的应用。^_^)
fromtimeimportctime,sleepdefmusic():foriinrange(2):print”Iwaslisteningtomusic.%s”%ctime()
sleep(1)defmove():foriinrange(2):print”Iwasatthemovies!%s”%ctime()
sleep(5)if__name__==’__main__’:
music()
move()print”allover%s”%ctime()
咱们先听了一首音乐,经过for循环来控制音乐的播映了两次,每首音乐播映需求1秒钟,sleep()来控制音乐播映的时长。接着咱们又看了一场电影,
每一场电影需求5秒钟,由于太好看了,所以我也经过for循环看两遍。在整个休闲娱乐活动完毕后,我经过
print”allover%s”%ctime()
看了一下当时时刻,差不多该睡觉了。
运转成果:
>>===========================RESTART================================
>>>Iwaslisteningtomusic.ThuApr1710:47:082014Iwaslisteningtomusic.ThuApr1710:47:092014Iwasatthemovies!ThuApr1710:47:102014Iwasatthemovies!ThuApr1710:47:152014alloverThuApr1710:47:202014
其实,music()和move()更应该被看作是音乐和视频播映器,至于要播映什么歌曲和视频应该由咱们运用时决议。所以,咱们对上面代码做了改造:
#coding=utf-8importthreadingfromtimeimportctime,sleepdefmusic(func):foriinrange(2):print”Iwaslisteningto%s.%s”%(func,ctime())
sleep(1)defmove(func):foriinrange(2):print”Iwasatthe%s!%s”%(func,ctime())
sleep(5)if__name__==’__main__’:
music(u’爱情生意’)
move(u’阿凡达’)print”allover%s”%ctime()
对music()和move()进行了传参处理。体会我国经典歌曲和欧美大片文明。
运转成果:
>>>========================RESTART================================
>>>Iwaslisteningto爱情生意.ThuApr1711:48:592014Iwaslisteningto爱情生意.ThuApr1711:49:002014Iwasatthe阿凡达!ThuApr1711:49:012014Iwasatthe阿凡达!ThuApr1711:49:062014alloverThuApr1711:49:112014
多线程
科技在发展,年代在进步,咱们的CPU也越来越快,CPU抱怨,P大点事儿占了我必定的时刻,其实我一起干多个活都没问题的;所以,操作系统就进入了多任务年代。咱们听着音乐吃着火锅的不在是梦想。
python提供了两个模块来完结多线程thread和threading,thread有一些缺点,在threading得到了弥补,为了不糟蹋你和时刻,所以咱们直接学习threading就可以了。
持续对上面的比如进行改造,引入threadring来一起播映音乐和视频:
#coding=utf-8importthreadingfromtimeimportctime,sleepdefmusic(func):foriinrange(2):print”Iwaslisteningto%s.%s”%(func,ctime())
sleep(1)defmove(func):foriinrange(2):print”Iwasatthe%s!%s”%(func,ctime())
sleep(5)
threads=[]
t1=threading.Thread(target=music,args=(u’爱情生意’,))
threads.append(t1)
t2=threading.Thread(target=move,args=(u’阿凡达’,))
threads.append(t2)if__name__==’__main__’:fortinthreads:
t.setDaemon(True)
t.start()print”allover%s”%ctime()
importthreading
首先导入threading模块,这是运用多线程的前提。
threads=[]
t1=threading.Thread(target=music,args=(u’爱情生意’,))
threads.append(t1)
创立了threads数组,创立线程t1,运用threading.Thread()办法,在这个办法中调用music办法target=music,args办法对music进行传参。把创建好的线程t1装到threads数组中。
接着以同样的办法创立线程t2,并把t2也装到threads数组。
fortinthreads:
t.setDaemon(True)
t.start()
最终经过for循环遍历数组。(数组被装载了t1和t2两个线程)
setDaemon()
setDaemon(True)将线程声明为看护线程,有必要在start()办法调用之前设置,如果不设置为看护线程程序会被无限挂起。子线程发动后,父线程也持续履行下去,当父线程履行完最终一条句子print”allover%s”%ctime()后,没有等候子线程,直接就退出了,一起子线程也一同完毕。
start()
开始线程活动。
运转成果:
>>>=========================RESTART================================
>>>Iwaslisteningto爱情生意.ThuApr1712:51:452014Iwasatthe阿凡达!ThuApr1712:51:452014alloverThuApr1712:51:452014
从履行成果来看,子线程(muisc、move)和主线程(print”allover%s”%ctime())都是同一时刻发动,但由于主线程履行完完毕,所以导致子线程也停止。
持续调整程序:
…if__name__==’__main__’:fortinthreads:
t.setDaemon(True)
t.start()fortinthreads:
t.join()print”allover%s”%ctime()
咱们只对上面的程序加了个join()办法,用于等候线程停止。join()的作用是,在子线程完结运转之前,这个子线程的父线程将一直被堵塞。
留意:join()办法的位置是在for循环外的,也就是说有必要等候for循环里的两个进程都完毕后,才去履行主进程。python

python多线程实例详解

一、进程与线程关系
一个进程至少包括一个线程。
二、线程基础
1、线程的状况
线程有5种状况,状况转化的过程如下图所示:
2、线程同步(锁)
多线程的优势在于能够一起运转多个使命(至少感觉起来是这样)。但是当线程需求共享数据时,或许存在数据不同步的问题。考虑这样一种状况:一个列表里一切元素都是0,线程”set”从后向前把一切元素改成1,而线程”print”负责从前往后读取列表并打印。那么,或许线程”set”开端改的时分,线程”print”便来打印列表了,输出就成了一半0一半1,这便是数据的不同步。为了防止这种状况,引入了锁的概念。
锁有两种状况——确定和未确定。每当一个线程比如”set”要拜访共享数据时,有必要先取得确定;假如现已有其他线程比如”print”取得确定了,那么就让线程”set”暂停,也便是同步堵塞;比及线程”print”拜访完毕,开释锁今后,再让线程”set”持续。经过这样的处理,打印列表时要么悉数输出0,要么悉数输出1,不会再出现一半0一半1的尴尬局面。
线程与锁的交互如下图所示:
线程与锁
3、线程通讯(条件变量)
然而还有另外一种尴尬的状况:列表并不是一开端就有的;而是经过线程”create”创立的。假如”set”或许”print”在”create”还没有运转的时分就拜访列表,将会出现一个反常。运用锁能够处理这个问题,但是”set”和”print”将需求一个无限循环——他们不知道”create”什么时分会运转,让”create”在运转后告诉”set”和”print”显然是一个更好的处理方案。所以,引入了条件变量。
条件变量允许线程比如”set”和”print”在条件不满足的时分(列表为None时)等候,比及条件满足的时分(列表现已创立)发出一个告诉,告诉”set”和”print”条件现已有了,你们该起床干活了;然后”set”和”print”才持续运转。
线程与条件变量的交互如下图所示:
需求条件的线程
创造条件的线程
4、线程运转和堵塞的状况转化
最终看看线程运转和堵塞状况的转化
线程运转与堵塞状况转化
堵塞有三种状况:
同步堵塞(确定池)是指处于竞赛确定的状况,线程恳求确守时将进入这个状况,一旦成功取得确定又康复到运转状况;
等候堵塞(等候池)是指等候其他线程告诉的状况,线程取得条件确定后,调用“等候”将进入这个状况,一旦其他线程发出告诉,线程将进入同步堵塞状况,再次竞赛条件确定;
而其他堵塞是指调用time.sleep()、anotherthread.join()或等候IO时的堵塞,这个状况下线程不会开释已取得的确定。
tips:假如能了解这些内容,接下来的主题将对错常轻松的;并且,这些内容在大部分流行的编程语言里都是相同的。(意思便对错看懂不可>_<嫌作者水平低找他人的教程也要看懂)
三、thread
Python经过两个标准库thread和threading供给对线程的支持。thread供给了初级其他、原始的线程以及一个简略的锁。
#encoding:UTF-8importthreadimporttime#一个用于在线程中履行的函数deffunc():foriinrange(5):print’func’time.sleep(1)#完毕当时线程#这个办法与thread.exit_thread()等价thread.exit()#当func回来时,线程同样会完毕#发动一个线程,线程当即开端运转#这个办法与thread.start_new_thread()等价#第一个参数是办法,第二个参数是办法的参数thread.start_new(func,())#办法没有参数时需求传入空tuple#创立一个锁(LockType,不能直接实例化)#这个办法与thread.allocate_lock()等价lock=thread.allocate()#判断锁是确定状况还是开释状况printlock.locked()#锁通常用于控制对共享资源的拜访count=0#取得锁,成功取得确定后回来True#可选的timeout参数不填时将一向堵塞直到取得确定#不然超时后将回来Falseiflock.acquire():
count+=1#开释锁lock.release()#thread模块供给的线程都将在主线程完毕后一起完毕time.sleep(6)
thread模块供给的其他办法:
thread.interrupt_main():在其他线程中停止主线程。
thread.get_ident():取得一个代表当时线程的魔法数字,常用于从一个字典中取得线程相关的数据。这个数字本身没有任何含义,并且当线程完毕后会被新线程复用。
thread还供给了一个ThreadLocal类用于办理线程相关的数据,名为thread._local,threading中引证了这个类。
因为thread供给的线程功能不多,无法在主线程完毕后持续运转,不供给条件变量等等原因,一般不运用thread模块,这里就不多介绍了。
四、threading
threading基于Java的线程模型设计。锁(Lock)和条件变量(Condition)在Java中是目标的根本行为(每一个目标都自带了锁和条件变量),而在Python中则是独立的目标。PythonThread供给了JavaThread的行为的子集;没有优先级、线程组,线程也不能被中止、暂停、康复、中断。JavaThread中的部分被Python完成了的静态办法在threading中以模块办法的方式供给。
threading模块供给的常用办法:
threading.currentThread():回来当时的线程变量。
threading.enumerate():回来一个包括正在运转的线程的list。正在运转指线程发动后、完毕前,不包括发动前和停止后的线程。
threading.activeCount():回来正在运转的线程数量,与len(threading.enumerate())有相同的结果。
threading模块供给的类:
Thread,Lock,Rlock,Condition,[Bounded]Semaphore,Event,Timer,local.
1、Thread
Thread是线程类,与Java相似,有两种运用办法,直接传入要运转的办法或从Thread承继并掩盖run():
#encoding:UTF-8importthreading#办法1:将要履行的办法作为参数传给Thread的结构办法deffunc():print’func()passedtoThread’t=threading.Thread(target=func)
t.start()#办法2:从Thread承继,并重写run()classMyThread(threading.Thread):defrun(self):print’MyThreadextendedfromThread’t=MyThread()
t.start()
结构办法:
Thread(group=None,target=None,name=None,args=(),kwargs={})
group:线程组,现在还没有完成,库引证中提示有必要是None;
target:要履行的办法;
name:线程名;
args/kwargs:要传入办法的参数。
实例办法:
isAlive():回来线程是否在运转。正在运转指发动后、停止前。
get/setName(name):获取/设置线程名。
is/setDaemon(bool):获取/设置是否看护线程。初始值从创立该线程的线程承继。当没有非看护线程仍在运转时,程序将停止。
start():发动线程。
join([timeout]):堵塞当时上下文环境的线程,直到调用此办法的线程停止或到达指定的timeout(可选参数)。
一个运用join()的比如:
#encoding:UTF-8importthreadingimporttimedefcontext(tJoin):print’inthreadContext.’tJoin.start()#将堵塞tContext直到threadJoin停止。tJoin.join()#tJoin停止后持续履行。print’outthreadContext.’defjoin():print’inthreadJoin.’time.sleep(1)print’outthreadJoin.’#tJoin和tContext分别为两个不同的线程tJoin=threading.Thread(target=join)
tContext=threading.Thread(target=context,args=(tJoin,))
tContext.start()
运转结果:
inthreadContext.inthreadJoin.outthreadJoin.outthreadContext.
2、Lock
Lock(指令锁)是可用的最初级的同步指令。Lock处于确定状况时,不被特定的线程具有。Lock包括两种状况——确定和非确定,以及两个根本的办法。
能够认为Lock有一个确定池,当线程恳求确守时,将线程至于池中,直到取得确定后出池。池中的线程处于状况图中的同步堵塞状况。
结构办法:
Lock()
实例办法:
acquire([timeout]):使线程进入同步堵塞状况,测验取得确定。
release():开释锁。运用前线程有必要已取得确定,不然将抛出反常。
#encoding:UTF-8importthreadingimporttime
data=0lock=threading.Lock()deffunc():globaldataprint’%sacquirelock…’%threading.currentThread().getName()#调用acquire([timeout])时,线程将一向堵塞,#直到取得确定或许直到timeout秒后(timeout参数可选)。#回来是否取得锁。iflock.acquire():print’%sgetthelock.’%threading.currentThread().getName()
data+=1time.sleep(2)print’%sreleaselock…’%threading.currentThread().getName()#调用release()将开释锁。lock.release()
t1=threading.Thread(target=func)
t2=threading.Thread(target=func)
t3=threading.Thread(target=func)
t1.start()
t2.start()
t3.start()
多运转几次,你会看到打印的信息次序并不一致,这就证实了线程在确定池中谁将取得锁运转是由系统调度决定(随机,不确定)
RLock
RLock(可重入锁)是一个能够被同一个线程恳求多次的同步指令。RLock运用了“具有的线程”和“递归等级”的概念,处于确定状况时,RLock被某个线程具有。具有RLock的线程能够再次调用acquire(),开释锁时需求调用release()相同次数。
能够认为RLock包括一个确定池和一个初始值为0的计数器,每次成功调用acquire()/release(),计数器将+1/-1,为0时锁处于未确定状况。
结构办法:
RLock()
实例办法:
acquire([timeout])/release():跟Lock差不多。
#encoding:UTF-8importthreadingimporttime
rlock=threading.RLock()deffunc():#第一次恳求确定print’%sacquirelock…’%threading.currentThread().getName()ifrlock.acquire():print’%sgetthelock.’%threading.currentThread().getName()
time.sleep(2)#第二次恳求确定print’%sacquirelockagain…’%threading.currentThread().getName()ifrlock.acquire():print’%sgetthelock.’%threading.currentThread().getName()
time.sleep(2)#第一次开释锁print’%sreleaselock…’%threading.currentThread().getName()
rlock.release()
time.sleep(2)#第二次开释锁print’%sreleaselock…’%threading.currentThread().getName()
rlock.release()
t1=threading.Thread(target=func)
t2=threading.Thread(target=func)
t3=threading.Thread(target=func)
t1.start()
t2.start()
t3.start()
4、Condition
Condition(条件变量)通常与一个锁相关。需求在多个Contidion中共享一个锁时,能够传递一个Lock/RLock实例给结构办法,不然它将自己生成一个RLock实例。
能够认为,除了Lock带有的确定池外,Condition还包括一个等候池,池中的线程处于状况图中的等候堵塞状况,直到另一个线程调用notify()/notifyAll()告诉;得到告诉后线程进入确定池等候确定。
结构办法:
Condition([lock/rlock])
实例办法:
acquire([timeout])/release():调用相关的锁的相应办法。
wait([timeout]):调用这个办法将使线程进入Condition的等候池等候告诉,并开释锁。运用前线程有必要已取得确定,不然将抛出反常。
notify():调用这个办法将从等候池挑选一个线程并告诉,收到告诉的线程将主动调用acquire()测验取得确定(进入确定池);其他线程仍然在等候池中。调用这个办法不会开释确定。运用前线程有必要已取得确定,不然将抛出反常。
notifyAll():调用这个办法将告诉等候池中一切的线程,这些线程都将进入确定池测验取得确定。调用这个办法不会开释确定。运用前线程有必要已取得确定,不然将抛出反常。
比如是很常见的出产者/顾客模式:
#encoding:UTF-8importthreadingimporttime#产品product=None#条件变量con=threading.Condition()#出产者办法defproduce():globalproductifcon.acquire():whileTrue:ifproductisNone:print’produce…’product=’anything’#告诉顾客,产品现已出产con.notify()#等候告诉con.wait()
time.sleep(2)#顾客办法defconsume():globalproductifcon.acquire():whileTrue:ifproductisnotNone:print’consume…’product=None#告诉出产者,产品现已没了con.notify()#等候告诉con.wait()
time.sleep(2)
t1=threading.Thread(target=produce)
t2=threading.Thread(target=consume)
t2.start()
t1.start()
5、Semaphore/BoundedSemaphore
Semaphore(信号量)是计算机科学史上最古老的同步指令之一。Semaphore办理一个内置的计数器,每当调用acquire()时-1,调用release()时+1。计数器不能小于0;当计数器为0时,acquire()将堵塞线程至同步确定状况,直到其他线程调用release()。
基于这个特色,Semaphore经常用来同步一些有“访客上限”的目标,比如连接池。
BoundedSemaphore与Semaphore的唯一差异在于前者将在调用release()时查看计数器的值是否超过了计数器的初始值,假如超过了将抛出一个反常。
结构办法:
Semaphore(value=1):value是计数器的初始值。
实例办法:
acquire([timeout]):恳求Semaphore。假如计数器为0,将堵塞线程至同步堵塞状况;不然将计数器-1并当即回来。
release():开释Semaphore,将计数器+1,假如运用BoundedSemaphore,还将进行开释次数查看。release()办法不查看线程是否已取得Semaphore。
#encoding:UTF-8importthreadingimporttime#计数器初值为2semaphore=threading.Semaphore(2)deffunc():#恳求Semaphore,成功后计数器-1;计数器为0时堵塞print’%sacquiresemaphore…’%threading.currentThread().getName()ifsemaphore.acquire():print’%sgetsemaphore’%threading.currentThread().getName()
time.sleep(4)#开释Semaphore,计数器+1print’%sreleasesemaphore’%threading.currentThread().getName()
semaphore.release()
t1=threading.Thread(target=func)
t2=threading.Thread(target=func)
t3=threading.Thread(target=func)
t4=threading.Thread(target=func)
t1.start()
t2.start()
t3.start()
t4.start()
time.sleep(2)#没有取得semaphore的主线程也能够调用release#若运用BoundedSemaphore,t4开释semaphore时将抛出反常print’MainThreadreleasesemaphorewithoutacquire’semaphore.release()
6、Event
Event(事情)是最简略的线程通讯机制之一:一个线程告诉事情,其他线程等候事情。Event内置了一个初始为False的标志,当调用set()时设为True,调用clear()时重置为False。wait()将堵塞线程至等候堵塞状况。
Event其实便是一个简化版的Condition。Event没有锁,无法使线程进入同步堵塞状况。

未经允许不得转载:IT技术网站 » python多线程(python多线程实例详解)
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

志在指尖 用双手敲打未来

登录/注册IT技术大全

热门IT技术

C#基础入门   SQL server数据库   系统SEO学习教程   WordPress小技巧   WordPress插件   脚本与源码下载