首頁  >  文章  >  後端開發  >  Python執行緒中定位與銷毀的詳細介紹(附範例)

Python執行緒中定位與銷毀的詳細介紹(附範例)

不言
不言轉載
2019-02-20 14:41:522425瀏覽

這篇文章帶給大家的內容是關於Python線程中定位與銷毀的詳細介紹(附示例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。

開工前我就覺得有什麼不太對勁,感覺要背鍋。這可不,上班第三天就捅鍋了。

我們有個了不起的後台程序,可以動態載入模組,並以執行緒方式運行,透過這種形式實現外掛程式的功能。而模組更新時候,後台程式本身不會退出,只會將模組對應的執行緒關閉、更新程式碼再啟動,6 得不行。

於是乎我就寫了個模組準備大展身手,結果忘記寫退出函數了,導致每次更新模組都新創建一個線程,除非重啟那個程序,否則那些線程就一直苟活著。

這可不行啊,得想個辦法清理呀,要不然怕是要炸了。

那麼怎麼清理呢?我能想到的就是兩步走:

  1. 找出需要清理的線程號tid;

  2. 銷毀它們;

找出線程ID

和平時的故障排查相似,先透過ps 指令看看目標行程的執行緒情況,因為已經是setName 設定過執行緒名,所以正常來說應該是看到對應的線程的。直接用下面程式​​碼來模擬這個執行緒:

Python 版本的多執行緒

#coding: utf8
import threading
import os
import time

def tt():
    info = threading.currentThread()
    while True:
        print 'pid: ', os.getpid()
        print info.name, info.ident
        time.sleep(3)

t1 = threading.Thread(target=tt)
t1.setName('OOOOOPPPPP')
t1.setDaemon(True)
t1.start()

t2 = threading.Thread(target=tt)
t2.setName('EEEEEEEEE')
t2.setDaemon(True)
t2.start()


t1.join()
t2.join()

#輸出:

root@10-46-33-56:~# python t.py
pid:  5613
OOOOOPPPPP 139693508122368
pid:  5613
EEEEEEEEE 139693497632512
...

可以看到在Python 裡面輸出的執行緒名稱就是我們設定的那樣,然而Ps 的結果卻是令我懷疑人生:

root@10-46-33-56:~# ps -Tp 5613
  PID  SPID TTY          TIME CMD
 5613  5613 pts/2    00:00:00 python
 5613  5614 pts/2    00:00:00 python
 5613  5615 pts/2    00:00:00 python

正常來說不該是這樣呀,我有點迷了,難道我一直都是記錯了?用別的語言版本的多執行緒來測試下:

C 版本的多執行緒

#include<stdio.h>
#include<sys>
#include<sys>
#include<pthread.h>

void *test(void *name)
{    
    pid_t pid, tid;
    pid = getpid();
    tid = syscall(__NR_gettid);
    char *tname = (char *)name;
    
    // 设置线程名字
    prctl(PR_SET_NAME, tname);
    
    while(1)
    {
        printf("pid: %d, thread_id: %u, t_name: %s\n", pid, tid, tname);
        sleep(3);
    }
}

int main()
{
    pthread_t t1, t2;
    void *ret;
    pthread_create(&t1, NULL, test,  (void *)"Love_test_1");
    pthread_create(&t2, NULL, test,  (void *)"Love_test_2");
    pthread_join(t1, &ret);
    pthread_join(t2, &ret);
}</pthread.h></sys></sys></stdio.h>

輸出:

root@10-46-33-56:~# gcc t.c -lpthread && ./a.out
pid: 5575, thread_id: 5577, t_name: Love_test_2
pid: 5575, thread_id: 5576, t_name: Love_test_1
pid: 5575, thread_id: 5577, t_name: Love_test_2
pid: 5575, thread_id: 5576, t_name: Love_test_1
...

用PS 指令再次驗證:

root@10-46-33-56:~# ps -Tp 5575
  PID  SPID TTY          TIME CMD
 5575  5575 pts/2    00:00:00 a.out
 5575  5576 pts/2    00:00:00 Love_test_1
 5575  5577 pts/2    00:00:00 Love_test_2

這個才是正確嘛,線程名確實是可以透過Ps 看出來的嘛!

不過為啥 Python 那個看不到呢?既然是透過setName 設定線程名的,那就看看定義咯:

[threading.py]
class Thread(_Verbose):
    ...
    @property
    def name(self):
        """A string used for identification purposes only.

        It has no semantics. Multiple threads may be given the same name. The
        initial name is set by the constructor.

        """
        assert self.__initialized, "Thread.__init__() not called"
        return self.__name

    @name.setter
    def name(self, name):
        assert self.__initialized, "Thread.__init__() not called"
        self.__name = str(name)
        
    def setName(self, name):
        self.name = name
    ...

看到這裡其實只是在Thread 物件的屬性設定了而已,並沒有動到根本,那肯定就是看不到咯~

這樣看起來,我們已經沒辦法透過ps/proc/ 這類手段在外部搜尋python 線程名了,所以我們只能在Python 內部來解決。

於是問題就變成了,怎麼能在 Python 內部拿到所有正在執行的執行緒呢?

threading.enumerate  可以完美解決這個問題! Why?

Because 在下面這個函數的 doc 裡面說得很清楚了,傳回所有活躍的執行緒物件,不包括終止和未啟動的。

[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()

因為拿到的是 Thread 的對象,所以我們透過這個能到該線程相關的資訊!

請看完整程式碼範例:

#coding: utf8

import threading
import os
import time


def get_thread():
    pid = os.getpid()
    while True:
        ts = threading.enumerate()
        print '------- Running threads On Pid: %d -------' % pid
        for t in ts:
            print t.name, t.ident
        print
        time.sleep(1)
        
def tt():
    info = threading.currentThread()
    pid = os.getpid()
    while True:
        print 'pid: {}, tid: {}, tname: {}'.format(pid, info.name, info.ident)
        time.sleep(3)
        return

t1 = threading.Thread(target=tt)
t1.setName('Thread-test1')
t1.setDaemon(True)
t1.start()

t2 = threading.Thread(target=tt)
t2.setName('Thread-test2')
t2.setDaemon(True)
t2.start()

t3 = threading.Thread(target=get_thread)
t3.setName('Checker')
t3.setDaemon(True)
t3.start()

t1.join()
t2.join()
t3.join()

輸出:

root@10-46-33-56:~# python t_show.py
pid: 6258, tid: Thread-test1, tname: 139907597162240
pid: 6258, tid: Thread-test2, tname: 139907586672384

------- Running threads On Pid: 6258 -------
MainThread 139907616806656
Thread-test1 139907597162240
Checker 139907576182528
Thread-test2 139907586672384

------- Running threads On Pid: 6258 -------
MainThread 139907616806656
Thread-test1 139907597162240
Checker 139907576182528
Thread-test2 139907586672384

------- Running threads On Pid: 6258 -------
MainThread 139907616806656
Thread-test1 139907597162240
Checker 139907576182528
Thread-test2 139907586672384

------- Running threads On Pid: 6258 -------
MainThread 139907616806656
Checker 139907576182528
...

程式碼看起來有點長,但是邏輯相當簡單,Thread-test1Thread-test2 都是印出目前的pid、執行緒id 和執行緒名字,然後3s 後退出,這個是想模擬執行緒正常退出。

Checker 執行緒則是每秒透過 threading.enumerate 輸出目前行程內所有活躍的執行緒。

可以明顯看到一開始是可以看到Thread-test1Thread-test2的訊息,當它兩個退出之後就只剩下 MainThreadChecker 本身而已了。

銷毀指定執行緒

既然能拿到名字和執行緒 id,那我們也就能幹掉指定的執行緒了!

假設現在Thread-test2 已經黑化,發瘋了,我們需要阻止它,那我們就可以透過這種方式解決了:

在上面的程式碼基礎上,增加和補上下列程式碼:

def _async_raise(tid, exctype):
    """raises the exception, performs cleanup if needed"""
    tid = ctypes.c_long(tid)
    if not inspect.isclass(exctype):
        exctype = type(exctype)
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
    if res == 0:
        raise ValueError("invalid thread id")
    elif res != 1:
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
        raise SystemError("PyThreadState_SetAsyncExc failed")

def stop_thread(thread):
    _async_raise(thread.ident, SystemExit)

def get_thread():
    pid = os.getpid()
    while True:
        ts = threading.enumerate()
        print '------- Running threads On Pid: %d -------' % pid
        for t in ts:
            print t.name, t.ident, t.is_alive()
            if t.name == 'Thread-test2':
                print 'I am go dying! Please take care of yourself and drink more hot water!'
                stop_thread(t)
        print
        time.sleep(1)

輸出

root@10-46-33-56:~# python t_show.py
pid: 6362, tid: 139901682108160, tname: Thread-test1
pid: 6362, tid: 139901671618304, tname: Thread-test2
------- Running threads On Pid: 6362 -------
MainThread 139901706389248 True
Thread-test1 139901682108160 True
Checker 139901661128448 True
Thread-test2 139901671618304 True
Thread-test2: I am go dying. Please take care of yourself and drink more hot water!

------- Running threads On Pid: 6362 -------
MainThread 139901706389248 True
Thread-test1 139901682108160 True
Checker 139901661128448 True
Thread-test2 139901671618304 True
Thread-test2: I am go dying. Please take care of yourself and drink more hot water!

pid: 6362, tid: 139901682108160, tname: Thread-test1
------- Running threads On Pid: 6362 -------
MainThread 139901706389248 True
Thread-test1 139901682108160 True
Checker 139901661128448 True
// Thread-test2 已经不在了

一餐操作下來,雖然我們這樣對待Thread-test2,但它還是關心著我們:多喝熱水

PS: 熱水雖好,八杯足矣,請勿貪杯哦。

書回正傳,上述的方法是極為粗暴的,為什麼這麼說呢?

因為它的原理是:利用Python 內建的API,觸發指定執行緒的異常,讓其可以自動退出;

Python執行緒中定位與銷毀的詳細介紹(附範例)

萬不得已真不要用這種方法,有一定機率觸發不可描述的問題。切記!別問我為什麼會知道...

為什麼停止執行緒這麼難

多執行緒本身設計就是在進程下的協作並發,是調度的最小單元,執行緒間分食著進程的資源,所以會有許多鎖定機制和狀態控制。

如果使用強製手段幹掉線程,那麼很大幾率就會出現意想不到的bug。 而且最重要的鎖定資源釋放可能也會出現意想不到問題。

我們甚至無法透過訊號殺死進程那樣直接殺線程,因為 kill 只有對付程序才能達到我們的預期,而對付線程明顯不可以,不管殺哪個線程,整個行程都會退出!

而因為有 GIL,使得許多童鞋都覺得 Python 的線程是Python 自行實現出來的,並非實際存在,Python 應該可以直接銷毀吧?

然而事實上 Python 的線程都是貨真價實的線程!

什麼意思呢? Python 的執行緒是作業系統透過 pthread 建立的原生執行緒。 Python  只是透過 GIL 來約束這些線程,來決定什麼時候開始調度,比方說運行了多少個指令就交出 GIL,至於誰奪得花魁,得聽操作系統的。

如果是單純的線程,其實係統是有辦法終止的,例如: pthread_exit,pthread_kill  或pthread_cancel,  詳情可看: https://www.cnblogs.com/Creat...

可惜的是: Python 層面並沒有這些方法的封裝!我的天,好氣!可能人家覺得,線程就該溫柔對待吧。

如何溫柔退出線程

想要溫柔退出線程,其實差不多就是一句廢話了~

要么運行完退出,要么設置標誌位,時常檢查標記位,該退出的就退出咯。

擴充功能

《如何正確的終止正在運行的子執行緒》:https://www.cnblogs.com/Creat...
《不要粗暴的銷毀python執行緒》 :http://xiaorui.cc/2017/02/22/...

#歡迎各位大神指點交流, QQ討論群: 258498217
轉載請註明來源: https://segmentfault.com/a/11...







######################                                            上##############################################################

##                                                                                                                                               

  •                                                                   
  • #

    Python:執行緒之定位與銷毀
  • Python執行緒中定位與銷毀的詳細介紹(附範例)

  • #c

##linux

############################linux######################## ##########                                                                                 python############             266 次閱讀                                                 ·                                                 時所學。                                                                                        #################



                           8#                        

##                        

#                        #                        

#                        #                        #                    

背景

##開工前我覺得有什麼不太對勁,感覺要背鍋。這可不,上班第三天就捅鍋了。

我們有個了不起的後台程序,可以動態載入模組,並以執行緒方式運行,透過這種形式實現外掛程式的功能。而模組更新時候,後台程式本身不會退出,只會將模組對應的執行緒關閉、更新程式碼再啟動,6 得不行。

於是乎我就寫了個模組準備大展身手,結果忘記寫退出函數了,導致每次更新模組都新創建一個線程,除非重啟那個程序,否則那些線程就一直苟活著。

這可不行啊,得想個辦法清理呀,要不然怕是要炸了。

那麼怎麼清理呢?我能想到的就是兩步走:

找出需要清理的線程號tid;

銷毀它們;

找出線程ID

和平時的故障排查相似,先透過ps 指令看看目標行程的執行緒情況,因為已經是setName 設定過執行緒名,所以正常來說應該是看到對應的線程的。直接用下面程式​​碼來模擬這個執行緒:

Python 版本的多執行緒

#coding: utf8
import threading
import os
import time

def tt():
    info = threading.currentThread()
    while True:
        print 'pid: ', os.getpid()
        print info.name, info.ident
        time.sleep(3)

t1 = threading.Thread(target=tt)
t1.setName('OOOOOPPPPP')
t1.setDaemon(True)
t1.start()

t2 = threading.Thread(target=tt)
t2.setName('EEEEEEEEE')
t2.setDaemon(True)
t2.start()


t1.join()
t2.join()
#輸出:
root@10-46-33-56:~# python t.py
pid:  5613
OOOOOPPPPP 139693508122368
pid:  5613
EEEEEEEEE 139693497632512
...
可以看到在Python 裡面輸出的執行緒名稱就是我們設定的那樣,然而Ps 的結果卻是令我懷疑人生:
root@10-46-33-56:~# ps -Tp 5613
  PID  SPID TTY          TIME CMD
 5613  5613 pts/2    00:00:00 python
 5613  5614 pts/2    00:00:00 python
 5613  5615 pts/2    00:00:00 python
正常來說不該是這樣呀,我有點迷了,難道我一直都是記錯了?用別的語言版本的多執行緒來測試下:C 版本的多執行緒

#include<stdio.h>
#include<sys>
#include<sys>
#include<pthread.h>

void *test(void *name)
{    
    pid_t pid, tid;
    pid = getpid();
    tid = syscall(__NR_gettid);
    char *tname = (char *)name;
    
    // 设置线程名字
    prctl(PR_SET_NAME, tname);
    
    while(1)
    {
        printf("pid: %d, thread_id: %u, t_name: %s\n", pid, tid, tname);
        sleep(3);
    }
}

int main()
{
    pthread_t t1, t2;
    void *ret;
    pthread_create(&t1, NULL, test,  (void *)"Love_test_1");
    pthread_create(&t2, NULL, test,  (void *)"Love_test_2");
    pthread_join(t1, &ret);
    pthread_join(t2, &ret);
}</pthread.h></sys></sys></stdio.h>

輸出:

root@10-46-33-56:~# gcc t.c -lpthread && ./a.out
pid: 5575, thread_id: 5577, t_name: Love_test_2
pid: 5575, thread_id: 5576, t_name: Love_test_1
pid: 5575, thread_id: 5577, t_name: Love_test_2
pid: 5575, thread_id: 5576, t_name: Love_test_1
...
用PS 指令再次驗證:

root@10-46-33-56:~# ps -Tp 5575
  PID  SPID TTY          TIME CMD
 5575  5575 pts/2    00:00:00 a.out
 5575  5576 pts/2    00:00:00 Love_test_1
 5575  5577 pts/2    00:00:00 Love_test_2
這個才是正確嘛,線程名確實是可以透過Ps 看出來的嘛! 不過為啥 Python 那個看不到呢?既然是透過

setName

設定線程名的,那就看看定義咯:

[threading.py]
class Thread(_Verbose):
    ...
    @property
    def name(self):
        """A string used for identification purposes only.

        It has no semantics. Multiple threads may be given the same name. The
        initial name is set by the constructor.

        """
        assert self.__initialized, "Thread.__init__() not called"
        return self.__name

    @name.setter
    def name(self, name):
        assert self.__initialized, "Thread.__init__() not called"
        self.__name = str(name)
        
    def setName(self, name):
        self.name = name
    ...
看到這裡其實只是在

Thread 物件的屬性設定了而已,並沒有動到根本,那肯定就是看不到咯~這樣看起來,我們已經沒辦法透過ps

/proc/

這類手段在外部搜尋python 線程名了,所以我們只能在Python 內部來解決。 ######於是問題就變成了,怎麼能在 Python 內部拿到所有正在執行的執行緒呢? #########threading.enumerate###  可以完美解決這個問題! Why?######Because 在下面這個函數的 doc 裡面說得很清楚了,傳回所有活躍的###執行緒物件###,不包括終止和未啟動的。 ###
[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()
###因為拿到的是 Thread 的對象,所以我們透過這個能到該線程相關的資訊! ######請看完整程式碼範例:###
#coding: utf8

import threading
import os
import time


def get_thread():
    pid = os.getpid()
    while True:
        ts = threading.enumerate()
        print '------- Running threads On Pid: %d -------' % pid
        for t in ts:
            print t.name, t.ident
        print
        time.sleep(1)
        
def tt():
    info = threading.currentThread()
    pid = os.getpid()
    while True:
        print 'pid: {}, tid: {}, tname: {}'.format(pid, info.name, info.ident)
        time.sleep(3)
        return

t1 = threading.Thread(target=tt)
t1.setName('Thread-test1')
t1.setDaemon(True)
t1.start()

t2 = threading.Thread(target=tt)
t2.setName('Thread-test2')
t2.setDaemon(True)
t2.start()

t3 = threading.Thread(target=get_thread)
t3.setName('Checker')
t3.setDaemon(True)
t3.start()

t1.join()
t2.join()
t3.join()
###輸出:###
root@10-46-33-56:~# python t_show.py
pid: 6258, tid: Thread-test1, tname: 139907597162240
pid: 6258, tid: Thread-test2, tname: 139907586672384

------- Running threads On Pid: 6258 -------
MainThread 139907616806656
Thread-test1 139907597162240
Checker 139907576182528
Thread-test2 139907586672384

------- Running threads On Pid: 6258 -------
MainThread 139907616806656
Thread-test1 139907597162240
Checker 139907576182528
Thread-test2 139907586672384

------- Running threads On Pid: 6258 -------
MainThread 139907616806656
Thread-test1 139907597162240
Checker 139907576182528
Thread-test2 139907586672384

------- Running threads On Pid: 6258 -------
MainThread 139907616806656
Checker 139907576182528
...
###程式碼看起來有點長,但是邏輯相當簡單,###Thread-test1### 和# ##Thread-test2### 都是印出目前的pid、執行緒id 和執行緒名字,然後3s 後退出,這個是想模擬執行緒正常退出。 ######而 ###Checker### 執行緒則是每秒透過 ###threading.enumerate### 輸出目前行程內所有活躍的執行緒。 ######可以明顯看到一開始是可以看到###Thread-test1### 和###Thread-test2###的訊息,當它兩個退出之後就只剩下### MainThread### 和###Checker### 本身而已了。 ######銷毀指定執行緒######既然能拿到名字和執行緒 id,那我們也就能幹掉指定的執行緒了! ######假設現在###Thread-test2### 已經黑化,發瘋了,我們需要阻止它,那我們就可以透過這種方式解決了:######在上面的程式碼基礎上,增加和補上下列程式碼:###
def _async_raise(tid, exctype):
    """raises the exception, performs cleanup if needed"""
    tid = ctypes.c_long(tid)
    if not inspect.isclass(exctype):
        exctype = type(exctype)
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
    if res == 0:
        raise ValueError("invalid thread id")
    elif res != 1:
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
        raise SystemError("PyThreadState_SetAsyncExc failed")

def stop_thread(thread):
    _async_raise(thread.ident, SystemExit)

def get_thread():
    pid = os.getpid()
    while True:
        ts = threading.enumerate()
        print '------- Running threads On Pid: %d -------' % pid
        for t in ts:
            print t.name, t.ident, t.is_alive()
            if t.name == 'Thread-test2':
                print 'I am go dying! Please take care of yourself and drink more hot water!'
                stop_thread(t)
        print
        time.sleep(1)
###輸出###
root@10-46-33-56:~# python t_show.py
pid: 6362, tid: 139901682108160, tname: Thread-test1
pid: 6362, tid: 139901671618304, tname: Thread-test2
------- Running threads On Pid: 6362 -------
MainThread 139901706389248 True
Thread-test1 139901682108160 True
Checker 139901661128448 True
Thread-test2 139901671618304 True
Thread-test2: I am go dying. Please take care of yourself and drink more hot water!

------- Running threads On Pid: 6362 -------
MainThread 139901706389248 True
Thread-test1 139901682108160 True
Checker 139901661128448 True
Thread-test2 139901671618304 True
Thread-test2: I am go dying. Please take care of yourself and drink more hot water!

pid: 6362, tid: 139901682108160, tname: Thread-test1
------- Running threads On Pid: 6362 -------
MainThread 139901706389248 True
Thread-test1 139901682108160 True
Checker 139901661128448 True
// Thread-test2 已经不在了
###一餐操作下來,雖然我們這樣對待###Thread-test2###,但它還是關心著我們:###多喝熱水###,######PS: 熱水雖好,八杯足矣,請勿貪杯哦。 ###

書回正傳,上述的方法是極為粗暴的,為什麼這麼說呢?

因為它的原理是:利用Python 內建的API,觸發指定執行緒的異常,讓其可以自動退出;

Python執行緒中定位與銷毀的詳細介紹(附範例)

萬不得已真不要用這種方法,有一定機率觸發不可描述的問題。切記!別問我為什麼會知道...

為什麼停止執行緒這麼難

多執行緒本身設計就是在進程下的協作並發,是調度的最小單元,執行緒間分食著進程的資源,所以會有許多鎖定機制和狀態控制。

如果使用強製手段幹掉線程,那麼很大幾率就會出現意想不到的bug。 而且最重要的鎖定資源釋放可能也會出現意想不到問題。

我們甚至無法透過訊號殺死進程那樣直接殺線程,因為 kill 只有對付程序才能達到我們的預期,而對付線程明顯不可以,不管殺哪個線程,整個進程都會退出!

而因為有 GIL,使得許多童鞋都覺得 Python 的線程是Python 自行實現出來的,並非實際存在,Python 應該可以直接銷毀吧?

然而事實上 Python 的線程都是貨真價實的線程!

什麼意思呢? Python 的執行緒是作業系統透過 pthread 建立的原生執行緒。 Python  只是透過 GIL 來約束這些線程,來決定什麼時候開始調度,比方說運行了多少個指令就交出 GIL,至於誰奪得花魁,得聽操作系統的。

如果是單純的線程,其實係統是有辦法終止的,例如: pthread_exit,pthread_kill  或pthread_cancel,  詳情可看: https://www.cnblogs.com/Creat...

可惜的是: Python 層面並沒有這些方法的封裝!我的天,好氣!可能人家覺得,線程就該溫柔對待吧。

如何溫柔退出線程

想要溫柔退出線程,其實差不多就是一句廢話了~

要么運行完退出,要么設置標誌位,時常檢查標記位,該退出的就退出咯。

擴充

《如何正確的終止正在運行的子執行緒》:https://www.cnblogs.com/Creat...
《不要粗暴的銷毀python執行緒》 :http://xiaorui.cc/2017/02/22/...

#歡迎各位大神指點交流, QQ討論群: 258498217
轉載請註明來源: https://segmentfault.com/a/11...

  • #保留所有權利


回報






如果你覺得我的文章對你有用,請隨意讚賞


你可能感興趣的



2 評論

                                                                       時間排序


           

##############################################################################################################################                                            ######################水平))                    ######                    ####  ‧  1 天前###                ################若是我可能kill -9了,寧可錯殺一千,不可放過一個,蛤蛤###

                       #                                                #                    #                     回覆                                    


#                                #                                    #                                        0                                             #                                #                                                        



##啊~ -9 流程裡一樣全死了~

##########啊~#########>

                                                                                                                                                                                                                  #                                    #                                         —                                                                                    上Python執行緒中定位與銷毀的詳細介紹(附範例)##1                                                                                

                                                

                                       

 ‧  1 天前中上

                                               

新增回覆

載入中...

#顯示更多評論

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

以上是Python執行緒中定位與銷毀的詳細介紹(附範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除

相關文章

看更多