天天看點

python 多線程就這麼簡單(續)

  之前講了多線程的一篇部落格,感覺講的意猶未盡,其實,多線程非常有意思。因為我們在使用電腦的過程中無時無刻都在多程序和多線程。我們可以接着之前的例子繼續講。請先看我的上一篇部落格。

  從上面例子中發現線程的建立是頗為麻煩的,每建立一個線程都需要建立一個tx(t1、t2、...),如果建立的線程多時候這樣極其不友善。下面對通過例子進行繼續改進:

player.py

#coding=utf-8

from time import sleep, ctime 

import threading

def muisc(func):

    for i in range(2):

        print 'Start playing: %s! %s' %(func,ctime())

        sleep(2)

def move(func):

        sleep(5)

def player(name):

    r = name.split('.')[1]

    if r == 'mp3':

        muisc(name)

    else:

        if r == 'mp4':

            move(name)

        else:

            print 'error: The format is not recognized!'

list = ['愛情買賣.mp3','阿凡達.mp4']

threads = []

files = range(len(list))

#建立線程

for i in files:

    t = threading.Thread(target=player,args=(list[i],))

    threads.append(t)

if __name__ == '__main__': 

    #啟動線程

    for i in files:

        threads[i].start() 

    for i in files:

   threads[i].join()

    #主線程

    print 'end:%s' %ctime()

有趣的是我們又建立了一個player()函數,這個函數用于判斷播放檔案的類型。如果是mp3格式的,我們将調用music()函數,如果是mp4格式的我們調用move()函數。哪果兩種格式都不是那麼隻能告訴使用者你所提供有檔案我播放不了。

  然後,我們建立了一個list的檔案清單,注意為檔案加上字尾名。然後我們用len(list) 來計算list清單有多少個檔案,這是為了幫助我們确定循環次數。

  接着我們通過一個for循環,把list中的檔案添加到線程中數組threads[]中。接着啟動threads[]線程組,最後列印結束時間。

     split()可以将一個字元串拆分成兩部分,然後取其中的一部分。

>>> x = 'testing.py'

>>> s = x.split('.')[1]

>>> if s=='py':

    print s

運作結果:

現在向list數組中添加一個檔案,程式運作時會自動為其建立一個線程。

對if語句部分修改如下:

if __name__ == "__main__":

     for i in files:

         threads[i].start()

         print "##############"#-------添加标記

         print threads[i]#-------列印記憶體位址

         threads[i].join()

         print '%%%%%%%%%%%%%%%'#----添加标記

     print 'all subprocess run is over, and end:%s'%ctime()

運作代碼測試結果:

[root@Python stud001]# python player.py

Start playing:愛情買賣.mp3! Tue Apr 19 11:18:12 2016

 ##############

<Thread(Thread-1, started 140538910066432)>

Start playing 阿凡達.mp4! Tue Apr 19 11:18:12 2016

##############

<Thread(Thread-2, started 140538899576576)>

Start playing:愛情買賣.mp3! Tue Apr 19 11:18:14 2016

%%%%%%%%%%%%%%%

<Thread(Thread-1, stopped 140538910066432)>

Start playing 阿凡達.mp4! Tue Apr 19 11:18:18 2016

<Thread(Thread-2, stopped 140538899576576)>

all subprocess run is over, and end:Tue Apr 19 11:18:23 2016

[root@Python stud001]# 

從輸出結果可以看到,兩個for循環是依次執行,當第1個for循環完成之後,再執行第2個,啟用程序鎖功能就是在所有子線程開啟後再執行鎖動作,而不是開啟一個鎖一個,這裡要跟下面這種情況區分開來:

         print threads[i]

         print '##########'

     print 'all subprocess run is over, and end:%s'%ctime()  

[root@Python stud001]# python  player.py 

Start playing:愛情買賣.mp3! Tue Apr 19 11:22:13 2016

Start playing:愛情買賣.mp3! Tue Apr 19 11:22:15 2016

<Thread(Thread-1, stopped 140470393812736)>

##########

Start playing 阿凡達.mp4! Tue Apr 19 11:22:17 2016

Start playing 阿凡達.mp4! Tue Apr 19 11:22:22 2016

<Thread(Thread-2, stopped 140470393812736)>

all subprocess run is over, and end:Tue Apr 19 11:22:27 2016

[root@Python stud001]#

這裡是啟動一個線程就鎖一個線程,跟上面正好相反。

繼續改進例子:

  通過上面的程式,我們發現player()用于判斷檔案擴充名,然後調用music()和move() ,其實,music()和move()完整工作是相同的,我們為什麼不做一台超級播放器呢,不管什麼檔案都可以播放。經過改造,我的超級播放器誕生了。

super_player.py

def super_player(file,time):

        print 'Start playing: %s! %s' %(file,ctime())

        sleep(time)

#播放的檔案與播放時長

list = {'愛情買賣.mp3':3,'阿凡達.mp4':5,'我和你.mp3':4}

for file,time in list.items():

    t = threading.Thread(target=super_player,args=(file,time))

  for i in files:

      threads[i].join()

首先建立字典list ,用于定義要播放的檔案及時長(秒),通過字典的items()方法來循環的取file和time,取到的這兩個值用于建立線程。

  接着建立super_player()函數,用于接收file和time,用于确定要播放的檔案及時長。

  最後是線程啟動運作。運作結果:

Start playing: 愛情買賣.mp3! Fri Apr 25 09:45:09 2014

Start playing: 我和你.mp3! Fri Apr 25 09:45:09 2014

Start playing: 阿凡達.mp4! Fri Apr 25 09:45:09 2014

Start playing: 愛情買賣.mp3! Fri Apr 25 09:45:12 2014

Start playing: 我和你.mp3! Fri Apr 25 09:45:13 2014

Start playing: 阿凡達.mp4! Fri Apr 25 09:45:14 2014

end:Fri Apr 25 09:45:19 2014

建立多線程類

import threading 

class MyThread(threading.Thread):

    def __init__(self,func,args,name=''):

        threading.Thread.__init__(self)

        self.name=name

        self.func=func

        self.args=args

    def run(self):

        apply(self.func,self.args)

def super_play(file,time):

list = {'愛情買賣.mp3':3,'阿凡達.mp4':5}

for k,v in list.items():

    t = MyThread(super_play,(k,v),super_play.__name__)

    threads.append(t)        

MyThread(threading.Thread)

建立MyThread類,用于繼承threading.Thread類。

__init__()

使用類的初始化方法對func、args、name等參數進行初始化。  

apply()

  apply(func [, args [, kwargs ]]) 函數用于當函數參數已經存在于一個元組或字典中時,間接地調用函數。args是一個包含将要提供給函數的按位置傳遞的參數的元組。如果省略了args,任何參數都不會被傳遞,kwargs是一個包含關鍵字參數的字典。

apply() 用法:

#不帶參數的方法

>>> def say():

    print 'say in'

>>> apply(say)

say in

#函數隻帶元組的參數

>>> def say(a,b):

    print a,b

>>> apply(say,('hello','蟲師'))

hello 蟲師

#函數帶關鍵字參數

>>> def say(a=1,b=2):

>>> def haha(**kw):

    apply(say,(),kw)

>>> haha(a='a',b='b')

a b

MyThread(super_play,(k,v),super_play.__name__)

由于MyThread類繼承threading.Thread類,是以,我們可以使用MyThread類來建立線程。

      本文轉自027ryan  51CTO部落格,原文連結:http://blog.51cto.com/ucode/1765299,如需轉載請自行聯系原作者