成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Python:線程為什么搞個(gè)setDaemon

sunnyxd / 916人閱讀

摘要:之前一直很好奇,都沒有屬性,為什么會(huì)有呢結(jié)果這玩意就是真的是僅作用于層手動(dòng)笑臉結(jié)語區(qū)區(qū)一個(gè)可以引出很多本質(zhì)內(nèi)容的探索機(jī)會(huì),比如線程的創(chuàng)建過程,管理流程等。

前言

使用 Python 都不會(huì)錯(cuò)過線程這個(gè)知識(shí),但是每次談到線程,大家都下意識(shí)說 GIL 全局鎖,

但其實(shí)除了這個(gè)老生常談的話題,還有很多有價(jià)值的東西可以探索的,譬如:setDaemon()。

線程的使用 與 存在的問題

我們會(huì)寫這樣的代碼來啟動(dòng)多線程:

import time
import threading

def test():
    while True:
        print threading.currentThread()
        time.sleep(1)

if __name__ == "__main__":
    t1 = threading.Thread(target=test)
    t2 = threading.Thread(target=test)
    t1.start()
    t2.start()

輸出:

^C

^C^C^C^C^C^C    # ctrl-c 多次都無法中斷
 
^C
 

 

...(兩個(gè)線程競(jìng)相打?。?/pre>

通過 Threading 我們可以很簡(jiǎn)單的實(shí)現(xiàn)并發(fā)的需求,但是同時(shí)也給我們帶來了一個(gè)大難題: 怎么退出呢?

在上面的程序運(yùn)行中,我已經(jīng)嘗試按了多次的 ctrl-c,都無法中斷這程序工作的熱情!最后是迫不得已用 kill 才結(jié)束。

那么怎樣才能可以避免這種問題呢?或者說,怎樣才能在主線程退出的時(shí)候,子線程也自動(dòng)退出呢?

守護(hù)線程

有過相似經(jīng)驗(yàn)的老司機(jī)肯定就知道,setDaemon() 將線程搞成 守護(hù)線程 不就得了唄:

import time
import threading

def test():
    while True:
        print threading.currentThread()
        time.sleep(1)

if __name__ == "__main__":
    t1 = threading.Thread(target=test)
    t1.setDaemon(True)
    t1.start()

    t2 = threading.Thread(target=test)
    t2.setDaemon(True)
    t2.start()

輸出:

python2.7 1.py


(直接退出了)

直接退出?理所當(dāng)然,因?yàn)橹骶€程已經(jīng)執(zhí)行完了,確實(shí)是已經(jīng)結(jié)束了,正因?yàn)樵O(shè)置了守護(hù)線程,所以這時(shí)候子線程也一并退出了。

突如其來的 daemon

那么問題來了,我們以前學(xué) C 語言的時(shí)候,好像不用 Daemon 也可以啊,比如這個(gè):

#include 
#include 
#include 

void *test(void *args)
{
    while (1)
    {
        printf("ThreadID: %d
", syscall(SYS_gettid));
        sleep(1);
    }
}

int main()
{
    pthread_t t1 ;
    int ret = pthread_create(&t1, NULL, test, NULL);
    if (ret != 0)
    {
        printf("Thread create failed
");
    }
   
    // 避免直接退出
    sleep(2);
    printf("Main run..
");
}

輸出:

# gcc -lpthread test_pytha.out & ./a
ThreadID: 31233
ThreadID: 31233
Main run.. (毫不猶豫退出了)

既然 Python 也是用 C 寫的,為什么 Python 多線程退出需要 setDaemon ???

想要解決這個(gè)問題,我們怕不是要從主線程退出的一刻開始講起,從前....

反藤摸瓜

Python 解析器在結(jié)束的時(shí)候,會(huì)調(diào)用 wait_for_thread_shutdown 來做個(gè)例行清理:

// python2.7/python/pythonrun.c

static void
wait_for_thread_shutdown(void)
{
#ifdef WITH_THREAD
    PyObject *result;
    PyThreadState *tstate = PyThreadState_GET();
    PyObject *threading = PyMapping_GetItemString(tstate->interp->modules,
                                                  "threading");
    if (threading == NULL) {
        /* threading not imported */
        PyErr_Clear();
        return;
    }
    result = PyObject_CallMethod(threading, "_shutdown", "");
    if (result == NULL)
        PyErr_WriteUnraisable(threading);
    else
        Py_DECREF(result);
    Py_DECREF(threading);
#endif
}

我們看到 #ifdef WITH_THREAD 就大概猜到對(duì)于是否多線程,這個(gè)函數(shù)是運(yùn)行了不同的邏輯的

很明顯,我們上面的腳本,就是命中了這個(gè)線程邏輯,所以它會(huì)動(dòng)態(tài) import threading 模塊,然后執(zhí)行 _shutdown 函數(shù)。

這個(gè)函數(shù)的內(nèi)容,我們可以從 threading 模塊看到:

# /usr/lib/python2.7/threading.py

_shutdown = _MainThread()._exitfunc

class _MainThread(Thread):

    def __init__(self):
        Thread.__init__(self, name="MainThread")
        self._Thread__started.set()
        self._set_ident()
        with _active_limbo_lock:
            _active[_get_ident()] = self

    def _set_daemon(self):
        return False

    def _exitfunc(self):
        self._Thread__stop()
        t = _pickSomeNonDaemonThread()
        if t:
            if __debug__:
                self._note("%s: waiting for other threads", self)
        while t:
            t.join()
            t = _pickSomeNonDaemonThread()
        if __debug__:
            self._note("%s: exiting", self)
        self._Thread__delete()

def _pickSomeNonDaemonThread():
    for t in enumerate():
        if not t.daemon and t.is_alive():
            return t
    return None

_shutdown 實(shí)際上也就是 _MainThread()._exitfunc 的內(nèi)容,主要是將 enumerate() 返回的所有結(jié)果,全部 join() 回收

enumerate() 是什么?

這個(gè)平時(shí)我們也會(huì)使用,就是當(dāng)前進(jìn)程的所有 符合條件 的 Python線程對(duì)象:

>>> print threading.enumerate()
[<_MainThread(MainThread, started 140691994822400)>]
# /usr/lib/python2.7/threading.py

def enumerate():
    """Return a list of all Thread objects currently alive.

    The list includes daemonic threads, dummy thread objects created by
    current_thread(), and the main thread. It excludes terminated threads and
    threads that have not yet been started.

    """
    with _active_limbo_lock:
        return _active.values() + _limbo.values()

符合條件??? 符合什么條件?? 不著急,容我娓娓道來:

從起源談存活條件

在 Python 的線程模型里面,雖然有 GIL 的干涉,但是線程卻是實(shí)實(shí)在在的原生線程

Python 只是多加一層封裝: t_bootstrap,然后再在這層封裝里面執(zhí)行真正的處理函數(shù)。

threading 模塊內(nèi),我們也能看到一個(gè)相似的:

# /usr/lib/python2.7/threading.py

class Thread(_Verbose):
    def start(self):
        ...省略
        with _active_limbo_lock:
            _limbo[self] = self             # 重點(diǎn)
        try:
            _start_new_thread(self.__bootstrap, ())
        except Exception:
            with _active_limbo_lock:
                del _limbo[self]            # 重點(diǎn)
            raise
        self.__started.wait()
        
    def __bootstrap(self):
        try:
            self.__bootstrap_inner()
        except:
            if self.__daemonic and _sys is None:
                return
            raise
         
    def __bootstrap_inner(self):
        try:
            ...省略
            with _active_limbo_lock:
                _active[self.__ident] = self # 重點(diǎn)
                del _limbo[self]             # 重點(diǎn)
            ...省略
            

在上面的一連串代碼中,_limbo_active 的變化都已經(jīng)標(biāo)記了重點(diǎn),我們可以得到下面的定義:

    _limbo : 就是調(diào)用了 start,但是還沒來得及 _start_new_thread 的對(duì)象
    _active: 活生生的線程對(duì)象

那么回到上文,當(dāng) _MainThread()._exitfunc 執(zhí)行時(shí),是會(huì)檢查整個(gè)進(jìn)程是否存在 _limbo + _active 的對(duì)象,

只要存在一個(gè),就會(huì)調(diào)用 join(), 這個(gè)也就是堵塞的原因。

setDaemon 用處

無限期堵塞不行,自作聰明幫用戶強(qiáng)殺線程也不是辦法,那么怎么做才會(huì)比較優(yōu)雅呢?

那就是提供一個(gè)途徑,讓用戶來設(shè)置隨進(jìn)程退出的標(biāo)記,那就是 setDaemon

class Thread():
    ...省略
    def setDaemon(self, daemonic):
        self.daemon = daemonic
        
    ...省略
  
# 其實(shí)上面也貼了,這里再貼一次
def _pickSomeNonDaemonThread():
    for t in enumerate():
        if not t.daemon and t.is_alive():
            return t
    return None

只要子線程,全部設(shè)置 setDaemon(True), 那么主線程一準(zhǔn)備退出,全都乖乖地由操作系統(tǒng)銷毀回收。

之前一直很好奇,pthread 都沒有 daemon 屬性,為什么 Python 會(huì)有呢?

結(jié)果這玩意就是真的是僅作用于 Python 層(手動(dòng)笑臉)

結(jié)語

區(qū)區(qū)一個(gè) setDaemon 可以引出很多本質(zhì)內(nèi)容的探索機(jī)會(huì),比如線程的創(chuàng)建過程,管理流程等。

這些都是很有意思的內(nèi)容,我們應(yīng)該大膽探索,不局限于使用~

歡迎各位大神指點(diǎn)交流, QQ討論群: 258498217
轉(zhuǎn)載請(qǐng)注明來源: https://segmentfault.com/a/11...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/45134.html

相關(guān)文章

  • python線程實(shí)現(xiàn)

    摘要:中的多線程我參考了中的介紹,介紹的很入門很詳細(xì)。如只設(shè)置了第個(gè)和第個(gè),沒有設(shè)置這只會(huì)掉第個(gè)子線程個(gè)人猜測(cè),當(dāng)程序運(yùn)行完主線程后則會(huì)檢查剩余的子線程,將最后面的且是子進(jìn)程刪掉。第個(gè)沒有掉是因?yàn)榫€程還在運(yùn)行并且是默認(rèn)狀態(tài)不能被的。 本人初學(xué)者開始第一篇博客,記錄學(xué)習(xí)的點(diǎn)點(diǎn)滴滴,以作為備忘錄,也希望能同大家一起分享。有理解錯(cuò)誤的地方希望大家指正。 python中的多線程我參考了(http:/...

    simon_chen 評(píng)論0 收藏0
  • Python線程之定位與銷毀

    摘要:而線程則是每秒通過輸出當(dāng)前進(jìn)程內(nèi)所有活躍的線程。如果使用強(qiáng)制手段干掉線程,那么很大幾率出現(xiàn)意想不到的。只是通過來約束這些線程,來決定什么時(shí)候開始調(diào)度,比方說運(yùn)行了多少個(gè)指令就交出,至于誰奪得花魁,得聽操作系統(tǒng)的。 背景 開工前我就覺得有什么不太對(duì)勁,感覺要背鍋。這可不,上班第三天就捅鍋了。 我們有個(gè)了不起的后臺(tái)程序,可以動(dòng)態(tài)加載模塊,并以線程方式運(yùn)行,通過這種形式實(shí)現(xiàn)插件的功能。而模塊...

    Heier 評(píng)論0 收藏0
  • python線程、鎖、event事件機(jī)制的簡(jiǎn)單使用

    摘要:從調(diào)用方法啟動(dòng)線程,到方法執(zhí)行完畢或遇到未處理異常而中斷這段時(shí)間內(nèi),線程是激活的調(diào)用將會(huì)使主調(diào)線程堵塞,直到被調(diào)用線程運(yùn)行結(jié)束或超時(shí)。對(duì)象實(shí)現(xiàn)了簡(jiǎn)單的線程通信機(jī)制,它提供了設(shè)置信號(hào),清除信號(hào),等待等用于實(shí)現(xiàn)線程間的通信。 線程和進(jìn)程 1、線程共享創(chuàng)建它的進(jìn)程的地址空間,進(jìn)程有自己的地址空間2、線程可以訪問進(jìn)程所有的數(shù)據(jù),線程可以相互訪問 3、線程之間的數(shù)據(jù)是獨(dú)立的 4、子進(jìn)程復(fù)制線程的...

    lowett 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

sunnyxd

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<