分類:
python
2014-10-15 00:03
823人閱讀
收藏
舉報
事情的起因是我在看下面一段代碼遇到的疑惑,,明明是while True,為什么代碼沒有死循環(huán),??
- class D(threading.Thread):
- def __init__(self, queue):
- threading.Thread.__init__(self)
- self.queue = queue
- def run(self):
- while True:
- url = self.queue.get()
- self.download_file(url)
- self.queue.task_done()
-
- def download_file(self, url):
- h = urllib2.urlopen(url)
- f = os.path.basename(url)+'.html'
- with open(f,'wb') as f:
- while True:
- c = h.read(1024)
- if not c:
- break
- f.write(c)
-
- if __name__ == "__main__":
- urls= ['http://www.baidu.com','http://www.sina.com']
- queue = Queue.Queue()
- for i in range(5):
- t = D(queue)
- t.setDaemon(True)
- t.start()
-
- for u in urls:
- queue.put(u)
-
- queue.join()
之前一直簡單認為setDaemon就是設(shè)置為后臺線程而已,,沒有進一步去挖掘里面的含義,。 可問題的關(guān)鍵就是setDaemon,在底層的thread模塊中,,只要主線程結(jié)束了,,所有的其它線程都會結(jié)束,這很明顯,主線程結(jié)束python將銷毀運行時環(huán)境,,主線程肯定會被結(jié)束,。 threading模塊的線程setDaemon就是為了解決這個問題的,如果setDaemon(True),,那么和之前一樣,,主線程結(jié)束,所有子線程都將結(jié)束,。如果setDaemon(False),,主線程將等待該線程結(jié)束,等同于你調(diào)用線程的join方法,。 所以如果將上面的setDaemon注釋和修改為False,,那么程序?qū)⑺姥h(huán)。 其實我們并不推薦上面的做法,,上面做法有點線程池的味道,,但如果你看過一些python的線程池實現(xiàn),while True 循環(huán)中肯定有檢測退出語句,,因為在python的世界里言明比隱晦更加pythonic,。但很不幸的是,上面的代碼就來 自與<<編寫高質(zhì)量代碼:改善Python程序的91個建議>>,,我并沒有噴這本書,,但我覺得代碼舉例的確有待商榷。 你可能好奇,,setDaemon(False)是如何等同于線程join的呢,?,不急,,且聽我慢慢道來,。 未解決這個問題,threading模塊引入了_MainThread對象
-
-
-
- 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 = _MainThread()._exitfunc
其實_MainThread并沒有干什么事,,唯一的貢獻就是在threading模塊導入時創(chuàng)建了一個實例,并將_exitfunc 賦值給_shutdown函數(shù),。_exitfunc將收集所有非daemon且alive的線程,,并調(diào)用線程的join方法。哦,,原來是_MainThread悄悄的在幕后奮斗著,,剩下的問題就是誰調(diào)用_shutdown函數(shù)的呢? 當python要銷毀運行時之前肯定會調(diào)用,,所以打開pythonrun.c,,你會發(fā)現(xiàn)如下函數(shù)
-
-
-
-
- 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) {
-
- PyErr_Clear();
- return;
- }
- result = PyObject_CallMethod(threading, "_shutdown", "");
- if (result == NULL)
- PyErr_WriteUnraisable(threading);
- else
- Py_DECREF(result);
- Py_DECREF(threading);
- #endif
- }
原來是這家伙在搞鬼,,漲見識了,原來在C中還有調(diào)用py代碼的需求啊,。沒辦法啊,,誰讓threading模塊是純py 代碼呢!??!
來自:http://blog.csdn.net/yueguanghaidao/article/details/40088431
|