導航:首頁 > 編程語言 > 線程傳參python

線程傳參python

發布時間:2022-07-06 03:07:44

1. python3 創建線程時不用args傳參,執行線程時為什麼不是同時執行

在Python多線程下,每個線程的執行方式:
1、獲取GIL
2、執行代碼直到sleep或者是python虛擬機將其掛起。
3、釋放GIL

可見,某個線程想要執行,必須先拿到GIL,我們可以把GIL看作是「通行證」,並且在一個python進程中,GIL只有一個。拿不到通行證的線程,就不允許進入CPU執行。

在Python2.x里,GIL的釋放邏輯是當前線程遇見IO操作或者ticks計數達到100(ticks可以看作是Python自身的一個計數器,專門做用於GIL,每次釋放後歸零,這個計數可以通過
sys.setcheckinterval 來調整),進行釋放。

而每次釋放GIL鎖,線程進行鎖競爭、切換線程,會消耗資源。並且由於GIL鎖存在,python里一個進程永遠只能同時執行一個線程(拿到GIL的線程才能執行),這就是為什麼在多核CPU上,python的多線程效率並不高。

那麼是不是python的多線程就完全沒用了呢?
在這里我們進行分類討論:
1、CPU密集型代碼(各種循環處理、計數等等),在這種情況下,由於計算工作多,ticks計數很快就會達到閾值,然後觸發GIL的釋放與再競爭(多個線程來回切換當然是需要消耗資源的),所以python下的多線程對CPU密集型代碼並不友好。

2、IO密集型代碼(文件處理、網路爬蟲等),多線程能夠有效提升效率(單線程下有IO操作會進行IO等待,造成不必要的時間浪費,而開啟多線程能在線程A等待時,自動切換到線程B,可以不浪費CPU的資源,從而能提升程序執行效率)。所以python的多線程對IO密集型代碼比較友好。

而在python3.x中,GIL不使用ticks計數,改為使用計時器(執行時間達到閾值後,當前線程釋放GIL),這樣對CPU密集型程序更加友好,但依然沒有解決GIL導致的同一時間只能執行一個線程的問題,所以效率依然不盡如人意。

請注意:多核多線程比單核多線程更差,原因是單核下多線程,每次釋放GIL,喚醒的那個線程都能獲取到GIL鎖,所以能夠無縫執行,但多核下,CPU0釋放GIL後,其他CPU上的線程都會進行競爭,但GIL可能會馬上又被CPU0拿到,導致其他幾個CPU上被喚醒後的線程會醒著等待到切換時間後又進入待調度狀態,這樣會造成線程顛簸(thrashing),導致效率更低

回到最開始的問題:經常我們會聽到老手說:「python下想要充分利用多核CPU,就用多進程」,原因是什麼呢?

原因是:每個進程有各自獨立的GIL,互不幹擾,這樣就可以真正意義上的並行執行,所以在python中,多進程的執行效率優於多線程(僅僅針對多核CPU而言)。

所以在這里說結論:多核下,想做並行提升效率,比較通用的方法是使用多進程,能夠有效提高執行效率

2. 如何向線程傳遞參數

一、通過構造方法傳遞數據
在創建線程時,必須要建立一個Thread類的或其子類的實例。因此,我們不難想到在調用start方法之前通過線程類的構造方法將數據傳入線程。並將傳入的數據使用類變數保存起來,以便線程使用(其實就是在run方法中使用)。下面的代碼演示了如何通過構造方法來傳遞數據:
package mythread;

public class MyThread1 extends Thread
{
private String name;

public MyThread1(String name)
{
this.name = name;
}
public void run()
{
System.out.println("hello " + name);
}
public static void main(String[] args)
{
Thread thread = new MyThread1("world");
thread.start();
}
}
由於這種方法是在創建線程對象的同時傳遞數據的,因此,在線程運行之前這些數據就就已經到位了,這樣就不會造成數據在線程運行後才傳入的現象。如果要傳遞更復雜的數據,可以使用集合、類等數據結構。使用構造方法來傳遞數據雖然比較安全,但如果要傳遞的數據比較多時,就會造成很多不便。由於Java沒有默認參數,要想實現類似默認參數的效果,就得使用重載,這樣不但使構造方法本身過於復雜,又會使構造方法在數量上大增。因此,要想避免這種情況,就得通過類方法或類變數來傳遞數據。
二、通過變數和方法傳遞數據
向對象中傳入數據一般有兩次機會,第一次機會是在建立對象時通過構造方法將數據傳入,另外一次機會就是在類中定義一系列的public的方法或變數(也可稱之為欄位)。然後在建立完對象後,通過對象實例逐個賦值。下面的代碼是對MyThread1類的改版,使用了一個setName方法來設置name變數:
package mythread;

public class MyThread2 implements Runnable
{
private String name;

public void setName(String name)
{
this.name = name;
}
public void run()
{
System.out.println("hello " + name);
}
public static void main(String[] args)
{
MyThread2 myThread = new MyThread2();
myThread.setName("world");
Thread thread = new Thread(myThread);
thread.start();
}
}
【注】:本文轉自網路。

3. python多線程thread.start_new_thread傳參的問題

因為thread.start_new_thread(ssh_cmd,(3,))開的線程會和主線程一起結束,所以等不到執行print number 程序就結束了

4. Python 多線程傳參問題

下面是從python threading模塊摘錄下來的

class threading.Thread(group=None, target=None,
name=None, args=(), kwargs={})

args is the argument tuple for the target invocation. Defaults to
().

kwargs is a dictionary of keyword arguments for the target
invocation. Defaults to {}.

簡單的說就是,線程函數的參數要麼是tuple類型要麼是dict類型,既然python文檔上已經規定好了,那麼就是不能變了,除非重大的版本升級,棄用現在這種方式,不過這是不可能的,再者可以查看threading.Thread類的初始化代碼

classThread(_Verbose):
def__init__(self,group=None,target=None,name=None,
args=(),kwargs=None,verbose=None):
assertgroupisNone,"groupargumentmustbeNonefornow"
_Verbose.__init__(self,verbose)
ifkwargsisNone:
kwargs={}
self.__target=target
self.__name=str(nameor_newname())
self.__args=args
self.__kwargs=kwargs
self.__daemonic=self._set_daemon()
self.__ident=None
self.__started=Event()
self.__stopped=False
self.__block=Condition(Lock())
self.__initialized=True
#sys.
#sys.exc_
self.__stderr=_sys.stderr

看到上面的args和kwargs的賦值情況嗎,你不能像**kwargs這樣來傳參的。

從上面來看,你要使用多線程你就必須遵守這個約定,線程函數參數要麼是tuple,要麼是字典,沒辦法改進。非要改進那就是使用全局變數,不用傳參,但是如果是這樣的話會涉及到線程安全的問題或者叫數據同步問題,如果不加鎖或者其他互斥量的話這個問題會很嚴重。所以還是遵守規定吧

5. python多線程 怎麼傳送多個參數

importthreadpool
importtime

defMain_Def(par1,par2,par3):
print"par1=%s,par2=%s,par3=%s"%(par1,par2,par3)


if__name__=='__main__':
#方法1
list_var1=['1','2','3']
list_var2=['4','5','6']
par_list=[(list_var1,None),(list_var2,None)]
#方法2
#dict_var1={'par1':'1','par2':'2','par3':'3'}
#dict_var2={'par1':'4','par2':'5','par3':'6'}
#par_list=[(None,dict_var1),(None,dict_var2)]

pool=threadpool.ThreadPool(2)
requests=threadpool.makeRequests(Main_Def,par_list)
[pool.putRequest(req)forreqinrequests]
time.sleep(1)
pool.wait()

6. python中使用_thread模塊創建進程怎麼使用可選參數

_thread.start_new_thread(fun1,('thread_1', 4, '參數3'))
_thread.start_new_thread(fun2,('thread_1', 2, '參數3'))

7. python 已經啟動的線程 怎麼往裡面傳參數

把參數放到Queue里,線程從Queue里獲得參數,Queue是線程安全的

8. python子線程如何發運行結果傳給主線程

可以這樣 子進程把信息寫入文件,然後發信號給父進程,父進程收到信號後讀文件。

9. Python多線程的一些問題

python提供了兩個模塊來實現多線程thread 和threading ,thread 有一些缺點,在threading 得到了彌補,為了不浪費你和時間,所以我們直接學習threading 就可以了。
繼續對上面的例子進行改造,引入threadring來同時播放音樂和視頻:
#coding=utf-8import threadingfrom time import ctime,sleepdef music(func): for i in range(2): print "I was listening to %s. %s" %(func,ctime())
sleep(1)def move(func): for i in range(2): print "I was at the %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__': for t in threads:
t.setDaemon(True)
t.start() print "all over %s" %ctime()

import threading
首先導入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數組。

for t in threads:
t.setDaemon(True)
t.start()
最後通過for循環遍歷數組。(數組被裝載了t1和t2兩個線程)

setDaemon()
setDaemon(True)將線程聲明為守護線程,必須在start() 方法調用之前設置,如果不設置為守護線程程序會被無限掛起。子線程啟動後,父線程也繼續執行下去,當父線程執行完最後一條語句print "all over %s" %ctime()後,沒有等待子線程,直接就退出了,同時子線程也一同結束。

start()
開始線程活動。

運行結果:
>>> ========================= RESTART ================================
>>> I was listening to 愛情買賣. Thu Apr 17 12:51:45 2014 I was at the 阿凡達! Thu Apr 17 12:51:45 2014 all over Thu Apr 17 12:51:45 2014

從執行結果來看,子線程(muisc 、move )和主線程(print "all over %s" %ctime())都是同一時間啟動,但由於主線程執行完結束,所以導致子線程也終止。

繼續調整程序:
...if __name__ == '__main__': for t in threads:
t.setDaemon(True)
t.start()

t.join() print "all over %s" %ctime()

我們只對上面的程序加了個join()方法,用於等待線程終止。join()的作用是,在子線程完成運行之前,這個子線程的父線程將一直被阻塞。
注意: join()方法的位置是在for循環外的,也就是說必須等待for循環里的兩個進程都結束後,才去執行主進程。
運行結果:
>>> ========================= RESTART ================================
>>> I was listening to 愛情買賣. Thu Apr 17 13:04:11 2014 I was at the 阿凡達! Thu Apr 17 13:04:11 2014I was listening to 愛情買賣. Thu Apr 17 13:04:12 2014I was at the 阿凡達! Thu Apr 17 13:04:16 2014all over Thu Apr 17 13:04:21 2014

從執行結果可看到,music 和move 是同時啟動的。
開始時間4分11秒,直到調用主進程為4分22秒,總耗時為10秒。從單線程時減少了2秒,我們可以把music的sleep()的時間調整為4秒。
...def music(func): for i in range(2): print "I was listening to %s. %s" %(func,ctime())
sleep(4)
...

子線程啟動11分27秒,主線程運行11分37秒。
雖然music每首歌曲從1秒延長到了4 ,但通多程線的方式運行腳本,總的時間沒變化。

10. python 像這樣定義多線程的類在調用時怎麼把調用父類的參數傳遞給子函數

你已經實現了啊。在__init__初始化參數里,將參數傳遞進去。

另外因為線程工作在主程序同一個空間里,所以可以用全局變數傳遞。比如定義一個global v,然後在主程序里設置好。
再在線程里用global v來引用。

如果在線程運行當中,動態的改參數。可以象是這里的thread_stop設置。由主進程與從進程單對單的傳遞信號。

另外還可以通過隊列。這個好處是有一個鎖,可以全局使用。

此外你還可以引入一個消息管理器。各個線程與主進程直接通過消息傳遞變數。

進程之間也可以通過共享內存來實現RPC通信,就是交換數據。

線程處理完的數據,如果主程序想處理。可以這樣。讓線程通過全局變數,通過隊列傳回來。

不過主進程通常還有一個任務,就是監督線程的完成退處,並管理線程中止信號。

比如你這個程序少了一個
thread.join() 這里的join可以加一個timeout,當超時時,主進程就可以脫身出來,做一些其它的事情,比如處理返回數值。 如果線程通過一個數組變數將狀態傳回主進程。這樣輪洵子線程狀態會比join的效率更高。

你這個程序里用文件傳遞也不是不可以。這是一個很好思路。當你傳遞變數困難時,可以用文件。或者是資料庫。

閱讀全文

與線程傳參python相關的資料

熱點內容
自己購買雲主伺服器推薦 瀏覽:419
個人所得稅java 瀏覽:759
多餘的伺服器滑道還有什麼用 瀏覽:189
pdf劈開合並 瀏覽:26
不能修改的pdf 瀏覽:748
同城公眾源碼 瀏覽:488
一個伺服器2個埠怎麼映射 瀏覽:297
java字元串ascii碼 瀏覽:78
台灣雲伺服器怎麼租伺服器 瀏覽:475
旅遊手機網站源碼 瀏覽:332
android關聯表 瀏覽:945
安卓導航無聲音怎麼維修 瀏覽:332
app怎麼裝視頻 瀏覽:430
安卓系統下的軟體怎麼移到桌面 瀏覽:96
windows拷貝到linux 瀏覽:772
mdr軟體解壓和別人不一樣 瀏覽:904
單片機串列通信有什麼好處 瀏覽:340
游戲開發程序員書籍 瀏覽:860
pdf中圖片修改 瀏覽:288
匯編編譯後 瀏覽:491