<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ### 9.3.4 Python 多線程編程 很多編程語言都支持多線程編程,Python 語言亦然。與其他編程語言相比,Python 的 多線程編程是非常簡單的。 Python 提供了兩個支持線程的模塊,一個是較老的 thread 模塊,另一個是較新的 threading 模塊。其中 threading 采用了面向對象實現,功能更強,建議讀者使用。 thread 模塊的用法 任何程序一旦開始執行,就構成了一個主線程。在主線程中隨時可以創建新的子線程去 執行特定任務,并且主線程和子線程是并發執行的。 每個線程的生命期包括創建、啟動、執行和結束四個階段。 當主線程結束退出時,它所創建的子線程是否繼續生存(如果還沒有結束的話)依賴于系統平臺,有的平臺直接結束各子線程,有的平臺則允許子線程繼續執行。 thread 模塊提供了一個函數 start_new_thread 用于創建和啟動新線程,其用法如下: start_new_thread(&lt;函數&gt;,&lt;參數&gt;) 本函數的具體功能是:創建一個新線程并立即返回,返回值是所創建的新線程的標識號(如 果需要可以賦值給一個變量)。新線程隨之啟動,所執行的任務就是&lt;函數&gt;的代碼,它應該 在程序中定義。調用&lt;函數&gt;時傳遞的實參由&lt;參數&gt;指定,&lt;參數&gt;是一個元組,如果&lt;函數&gt; 沒有形參,則&lt;參數&gt;為空元組。當&lt;函數&gt;執行完畢返回時,線程即告結束。 下面用一個例子來說明 thread 模塊的用法。程序 9.3 采用孫悟空拔毫毛變出小猴子的故事來演示主線程與它所創建的子線程的關系。主線程是孫悟空,子線程是小猴子。 【程序 9.3】eg9_3.py ``` # -*- coding: cp936 -*- import thread def task(tName,n): for i in range(n): print "%s:%d\n" % (tName,i) print "%s:任務完成!回真身去嘍...\n" % tName thread.interrupt_main() print "<老孫>:我是孫悟空!" print "<老孫>:我拔根毫毛變個小猴兒~~~" thread.start_new_thread(task,("<小猴>",3)) print "<老孫>:我睡會兒,小猴兒干完活再叫醒我~~~\n" while True: print "<老孫>:Zzzzzzz\n" ``` 程序執行后,孫悟空(主線程)先說了兩句話,然后創建小猴子,最后進入一個無窮循 環。小猴子創建后就立即啟動,執行函數 task,該函數的任務只是顯示簡單的信息。task 函 數的最后一行調用 thread 模塊中定義的 interrupt_main 函數,該函數的功能是在主線程中引 發 KeyboardInterrupt 異常,從而中斷主線程的執行。如果沒有這條語句,主線程將一直處于 無窮循環之中而無法結束。下面是程序的執行效果: ``` <老孫>:我是孫悟空! <老孫>:我拔根毫毛變個小猴兒~~~ <老孫>:我睡會兒,小猴兒干完活再叫醒我~~~ <小猴>:0 <老孫>:Zzzzzzz <小猴>:1 <老孫>:Zzzzzzz <小猴>:2 <老孫>:Zzzzzzz <小猴>:任務完成!回真身去嘍... <老孫>:Zzzzzzz Traceback (most recent call last): File "eg9_3.py", line 15, in <module> print "<老孫>:Zzzzzzz\n" KeyboardInterrupt ``` 從輸出結果可見,主線程和子線程確實是在以交叉方式并行執行。 順便說一下,由于程序 9.3 中使用了漢字,所以要在程序的第一行使用 ``` # -*- coding: cp936 -*- ``` 其作用是告訴 Python 解釋器代碼中使用了 cp936 編碼的字符(即漢字)。 下面再看一個例子。程序 9.4 的主線程創建了兩個子線程,兩個子線程都執行同一個函數 task,但以不同的節奏來顯示信息(每次循環中利用 sleep 分別休眠 2 秒和 4 秒)。注意, 與程序 9.3 不同,主線程創建完子線程后就結束了,留下兩個子線程繼續執行①。 【程序 9.4】eg9_4.py ``` # -*- coding: cp936 -*- import thread import time def task(tName,n,delay): for i in range(n): time.sleep(delay) print "%s:%d\n" % (tName,i) print "<老孫>:我是孫悟空!" print "<老孫>:我拔根毫毛變個小猴兒<哼>" thread.start_new_thread(task,("<哼>",5,2)) print "<老孫>:我再拔根毫毛變個小猴兒<哈>" thread.start_new_thread(task,("<哈>",5,4)) print "<老孫>:不管你們嘍,俺老孫去也~~~\n" ``` 下面是程序 9.4 的一次執行結果: ``` <老孫>:我是孫悟空! <老孫>:我拔根毫毛變個小猴兒<哼> <老孫>:我再拔根毫毛變個小猴兒<哈> <老孫>:不管你們嘍,俺老孫去也~~~ >>> <哼>:0 <哈>:0 <哼>:1 <哼>:2 <哈>:1 <哼>:3 <哼>:4 ![](img/程序設計思想與方法293617.png)① 在作者所用的計算機平臺(Windows XP + Python 2.7)上,主線程結束并不會導致子線程結束。 <哈>:2 <哈>:3 <哈>:4 KeyboardInterrupt >>> ``` 注意在“&lt;哼&gt;:0”之前的 Python 解釋器提示符“&gt;&gt;&gt;”,它表明主線程已經結束,控制 已返回給 Python 解釋器。但后續的輸出表明兩個子線程還在繼續執行。讀者可以分析一下 輸出結果所顯示的&lt;哼&gt;、&lt;哈&gt;交叉執行的情況,并想想為什么是這樣的結果。另外要注意, 由于主線程先于兩個子線程結束,導致兩個子線程執行結束后無法返回,這時可以用組合鍵 Ctrl-C 來強行中止子線程,屏幕上出現的 KeyboardInterrupt 就是因此而來。 threading 模塊的用法 雖然 thread 模塊用起來很方便,但它的功能有限,不如較新的 threading 模塊。threading 模塊采用面向對象方式來實現對線程的支持,其中定義了類 Thread,這個類封裝了有關線 程創建、啟動等功能。 Thread 類的使用有兩種方式。第一種用法是:直接利用 Thread 類來創建線程對象,并 在創建時向 Thread 構造器傳遞線程將要執行的函數;創建后通過調用線程對象的 start()方法 來啟動線程,以執行指定的任務。這是使用 threading 模塊來創建線程的最簡單方式。具體 語法如下: ``` t = Thread(target=&lt;函數&gt;,args=&lt;參數&gt;) t.start() ``` 可見,創建線程對象時,需向 Thread 類的構造器傳遞兩個參數:線程所執行的&lt;函數&gt;以及 該函數所需的&lt;參數&gt;。注意這里采用了關鍵字參數的傳遞方式。 下面的程序 9.5 與程序 9.4 的幾乎是一樣的,只是采用了 Thread 類來創建線程對象。 【程序 9.5】eg9_5.py ``` # -*- coding: cp936 -*- from threading import Thread from time import sleep def task(tName,n,delay): for i in range(n): sleep(delay) print "%s:%d\n" % (tName,i) print "<老孫>:我是孫悟空!" print "<老孫>:我拔根毫毛變個小猴兒<哼>" t1 = Thread(target=task,args=("<哼>",5,2)) print "<老孫>:我再拔根毫毛變個小猴兒<哈>" t2 = Thread(target=task,args=("<哈>",5,4)) t1.start() t2.start() print "<老孫>:不管你們嘍,俺老孫去也~~~\n" ``` 另一種使用 Thread 類的方法用到了線程對象的這么一個特性:當用 start()方法啟動線程 對象時,系統會自動調用 run()方法。因此,只要我們將線程需要執行的任務代碼寫到 run() 方法中,就能在創建并啟動線程對象后自動執行該任務。而將自己的代碼寫到 run()方法中 可以通過定義子類并重定義 run()的方式來做到。 總之,我們可以通過下列步驟來創建并啟動線程,執行指定的任務。 (1)定義 Thread 類的子類。這相當于定制我們自己的線程對象。 (2)重定義 init__()方法,即定制我們自己的構造器來初始化線程對象,例如可以添 加更多的參數。注意,定制構造器時首先應當執行基類的構造器 Thread.__init (),因為我 們定制的線程是原始線程的特例,首先要符合原始線程的要求。 (3)重定義 run()方法,即指定我們定制的線程將執行的代碼。 (4)利用自定義的線程類創建線程實例,并通過調用該實例的 start()方法(間接調用 run()方法)或直接調用 run()方法來啟動新線程執行任務。 程序 9.6 是采用上述方法的一個例子。 ``` # -*- coding: cp936 -*- from threading import Thread from time import sleep exitFlag = False class myThread(Thread): def __init__ (self,tName,n,delay): Thread. __init__ (self) self.name = tName self.loopnum = n self.delay = delay def run(self): print self.name + ": 上場...\n" task(self.name,self.loopnum,self.delay) print self.name + ": 退場...\n" def task(tName,n,delay): for i in range(n): if exitFlag: print "<哼>已退場,<哈>也提前結束吧~~~\n" return sleep(delay) print "%s:%d\n" % (tName,i) print "<老孫>:我是孫悟空!" print "<老孫>:我拔根毫毛變個小猴兒<哼>" t1 = myThread("<哼>",5,2) t1.start() print "<老孫>:我再拔根毫毛變個小猴兒<哈>\n" t2 = myThread("<哈>",10,4) t2.start() while t2.isAlive(): if not t1.isAlive(): exitFlag = True print "<老孫>:小猴兒們都回了,俺老孫去也~~~" ``` 當線程啟動后,就處于“活著(alive)”的狀態,直到線程的 run()方法執行結束(不管 是正常結束還是因為發生異常而終止),該線程才結束“活著”狀態。線程對象的 is_alive() 方法可用來檢查線程是否活著。程序 9.6 中,主線程在創建并啟動兩個子線程 t1 和 t2 之后, 就一直檢測 t2 是否還活著,如果 t2 活著就接著檢測 t1 是否活著。當 t2 活著而 t1 已經結束, 則將一個用作退出標志的全局變量 exitFlag 設置為 True(初始值為 False)。而 t2 執行任務循 環時會檢測 exitFlag 變量,一旦發現它變成了 True,就知道另一個線程已經結束,于是不再 執行后面的任務,直接結束返回。讀者應該注意到這件事的意義,它意味著多個線程之間是 可以進行協作、同步的,而不是各自只管悶著頭做自己的事情。 以下是程序 9.6 的一次執行結果: ``` <老孫>:我是孫悟空! <老孫>:我拔根毫毛變個小猴兒<哼> <哼>: 上場... <老孫>:我再拔根毫毛變個小猴兒<哈> <哈>: 上場... <哼>:0 <哼>:1 <哈>:0 <哼>:2 <哈>:1 <哼>:3 <哼>:4 <哼>: 退場... <哈>:2 <哼>已退場,<哈>也提前結束吧~~~ <哈>: 退場... <老孫>:小猴兒都回了,俺老孫去也~~~ >>> ``` 線程有名字,可通過 getName()和 setName()方法讀出或設置線程名。 總是有一個主線程對象,它對應于程序的初始控制流。 并發計算中的同步問題 多個線程之間如果只是彼此獨立地執行各自的任務,事情就簡單了。但是實際應用中常常需要多個線程之間進行合作,合作的線程往往要存取一些公共數據。由于多個線程的執行 順序是不可預測的,這就有可能導致公共數據處于不一致的狀態。因此,如果允許多個線程 并發讀寫公共數據,就必須對多線程的交互進行控制,以保護公共數據的正確性。 程序 9.6 演示了兩個線程通過一個全局變量進行協同的例子。 又如,Thread 對象具有一個 join()方法,一個線程對象 t1 可以調用另一個線程對象 t2 的 join()方法,這導致 t1 暫停執行,直至 t2 執行結束(或者執行一個指定的時間)。可見, join 方法能實現讓一個線程等待另一個線程以便進行某種同步的目的。 threading 模塊還實現了更一般的同步機制,在此就不介紹了。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看