python中線程和進程(一)
目錄
- 進程和線程
- Python中的線程
- 1. Thread類
- 2. 線程的啟動
- 3. 線程的傳參
- 4. 線程的屬性和方法
- 5. daemon線程和non-daemon線程
- 6. join方法
- 7. 定時器Timer
進程和線程
- 進程:進程是計算機中程序正在執行的實例,是系統進行資源分配和調度的基本單位。
- 線程:也被稱為輕量級進程,是程序執行流的最小單元。一個標準的線程由線程ID,當前指令指針,寄存器集合和堆棧組成。
線程和進程的關系:
現代操作系統中,每一個進程都認為自己獨占所有的計算機資源。進程好比一個國家,各個進程間不可以隨便的共享數據,而線程就像是省份,同一個進程內的線程可以共享進程的資源,每一個線程擁有自己獨立的堆棧。
進程和程序的關系:
程序是源代碼編譯後的文件,當該程序被操作系統加載到內存中,就是進程,進程中存放著指令和數據,它也是線程的容器。
Python中的線程
1. Thread類
python中線程的開發使用標準庫:threading
def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None):
- target:線程調用的對象,即目標函數
- name: 線程名
- args:為目標函數傳遞的實參,元組
- kwargs:為目標函數關鍵字傳參,字典
2. 線程的啟動
import threading
def worker():
print("I'm working")
print("Finished")
t = threading.Thread(target=worker,name='worker') #創建線程對象
t.start() # 啟動線程
可以通過threading.Thread創建一個線程對象,target指定目標函數,然後調用start
3. 線程的傳參
import threading
import time
def add(x,y):
print("{} + {} = {} 線程ID:{}".format(x,y,x+y,threading.current_thread().ident))
thread1 = threading.Thread(target=add,name='add1',args=(4,5)).start()
time.sleep(1)
thread2 = threading.Thread(target=add,name='add2',args=(10,),kwargs={'y':5}).start()
time.sleep(1)
thread3 = threading.Thread(target=add,name='add3',kwargs={'x':20,'y':5}).start()
線程傳參和函數傳參沒有什麽區別,本質上就是函數傳參。
4. 線程的屬性和方法
threading的屬性和方法
名稱 | 含義 |
---|---|
current_thread() | 返回當前線程對象 |
main_thread() | 返回主線程對象 |
active_count() | 當前處於alive狀態的線程數 |
enumerate() | 返回所有活著的線程的列表,不包括已經終止的線程和為開始的線程 |
get_ident() | 返回當前線程的ID |
Thread實例的屬性和方法
名稱 | 含義 |
---|---|
name | 名稱,僅僅是一個標識。可以通過getName()獲取,setName()設置該名稱 |
ident | 線程ID |
is_alive() | 返回線程是否活著 |
start() | 啟動線程。每個線程必須且只能執行該方法一次 |
run() | 運行線程函數 |
start和run的區別:
使用start啟動線程,會啟動一個新的線程,而使用run方法,並沒有啟動新的線程,只有在主線程上調用一個普通的函數。
5. daemon線程和non-daemon線程
在Python中,構造線程時,可以設置daemon屬性。默認daemon線程是None,即non-daemon線程。
import time
import threading
def foo():
time.sleep(5)
for i in range(20):
print(i)
t = threading.Thread(target=foo,daemon=True) #修改成None
t.start()
print("main thread Exit")
如果一個程序中只有daemon線程,那麽主線程退出的時候,會結束所有的daemon線程,退出。
總結:
在一個程序中,如果有non-daemon線程的時候,主線程退出時,不會殺掉所有的daemon線程,直到所有的non-daemon線程全部結束,如果還有daemon線程,主線程退出的時候,會結束所有的daemon線程,然後退出。
6. join方法
import time
import threading
def foo(n):
for i in range(n):
print(i)
time.sleep(1)
t = threading.Thread(target=foo,args=(10,),daemon=True)
t.start()
t.join() # 設置join
print("main thread Exit")
設置join後,daemon線程執行完了,程序才會退出。
join(timeout=None):
一個線程中調用另一個線程的join方法,此時調用者將會被阻塞,直到被調線程終止。一個線程可以被join多次。調用誰的join方法,就要等誰。
import time
import threading
def bar():
while True:
time.sleep(1)
print("bar")
def foo():
print("t1's daemon = {}".format(threading.current_thread().isDaemon()))
t2 = threading.Thread(target=bar)
t2.start()
print("t2's daemon = {}".format(t2.isDaemon()))
t1 = threading.Thread(target=foo,daemon=True)
t1.start()
time.sleep(3)
print("main thread exiting")
只要主程序退出,2個工作線程就結束。
import time
import threading
def bar():
while True:
time.sleep(1)
print("bar")
def foo():
print("t1's daemon = {}".format(threading.current_thread().isDaemon()))
t2 = threading.Thread(target=bar)
t2.start()
print("t2's daemon = {}".format(t2.isDaemon()))
t2.join()
t1 = threading.Thread(target=foo,daemon=True)
t1.start()
t1.join()
time.sleep(3)
print("main thread exiting")
通過相互調用join方法,使線程結束不了。
7. 定時器Timer
class Timer(Thread):
def __init__(self, interval, function, args=None, kwargs=None):
threading.Timer繼承自Thread,該類用來定義多久執行一個函數。
start方法執行之後,Timer對象就會處於等待狀態,等待了interval之後,開始執行function函數,如果在執行函數之前的等待階段,使用了cancel方法,就會跳過執行函數。
但是如果線程中的函數已經開始執行,cancel就沒有效果了。
import threading
import logging
import time
FORMAT = '%(asctime)s %(threadName)s %(thread)d %(message)s'
logging.basicConfig(format=FORMAT,level=logging.INFO)
def worker():
logging.info('in worker')
time.sleep(2)
t = threading.Timer(5,worker)
t.setName('w1')
t.cancel() # 提前取消
t.start()
print(threading.enumerate())
time.sleep(8)
print(threading.enumerate())
python中線程和進程(一)