進擊のpython
並發編程——開啟進程
學知識除了要縱向吸收,還要學會橫向對比
這樣類比學習就容易簡單的多
線程的學習就可以根據進程的學習來進行參考
這一節我們可以嘗試着使用threading模塊開啟線程
通過掌握threading模塊開啟線程的兩種方式
(我連上一句話都是照着線程的那個文章扒下來的)
threading模塊
multiprocess模塊的完全模仿了threading模塊的接口,二者在使用層面,有很大的相似性,因而不再詳細介紹
Thread類
class Thread:
def __init__(self, group=None, target=None, name=None,
args=(), kwargs=None, *, daemon=None):
if kwargs is None:
kwargs = {}
self._target = target
self._name = str(name or _newname())
self._args = args
self._kwargs = kwargs
if daemon is not None:
self._daemonic = daemon
else:
self._daemonic = current_thread().daemon
self._ident = None
self._tstate_lock = None
self._started = Event()
self._is_stopped = False
self._initialized = True
# sys.stderr is not stored in the class like
# sys.exc_info since it can be changed between instances
self._stderr = _sys.stderr
# For debugging and _after_fork()
_dangling.add(self)
介紹一下參數:
group:參數未使用,值始終是None
target:表示調用對象,即子線程要執行的任務(就是塞進去一個你想執行的函數)
args:表示調用對象的位置參數元祖(就是對函數進行傳參)
kwargs:表示調用對象的字典(就是對函數進行傳參)
name:子線程的名字
介紹一下屬性:
t.daemon:默認值為False,如果設為True,代表p為后台運行的守護進程
當p的父進程終止時,p也隨之終止,並且設定為True后,p不能創建自己的新進程
必須在start之前設置
2.name:線程的名稱
def start(self):
if not self._initialized:
raise RuntimeError("thread.__init__() not called")
if self._started.is_set():
raise RuntimeError("threads can only be started once")
with _active_limbo_lock:
_limbo[self] = self
try:
_start_new_thread(self._bootstrap, ())
except Exception:
with _active_limbo_lock:
del _limbo[self]
raise
self._started.wait()
def run(self):
try:
if self._target:
self._target(*self._args, **self._kwargs)
finally:
# Avoid a refcycle if the thread is running a function with
# an argument that has a member that points to the thread.
del self._target, self._args, self._kwargs
def join(self, timeout=None):
if not self._initialized:
raise RuntimeError("Thread.__init__() not called")
if not self._started.is_set():
raise RuntimeError("cannot join thread before it is started")
if self is current_thread():
raise RuntimeError("cannot join current thread")
if timeout is None:
self._wait_for_tstate_lock()
else:
# the behavior of a negative timeout isn't documented, but
# historically .join(timeout=x) for x<0 has acted as if timeout=0
self._wait_for_tstate_lock(timeout=max(timeout, 0))
def is_alive(self):
assert self._initialized, "Thread.__init__() not called"
if self._is_stopped or not self._started.is_set():
return False
self._wait_for_tstate_lock(False)
return not self._is_stopped
def isAlive(self):
import warnings
warnings.warn('isAlive() is deprecated, use is_alive() instead',
PendingDeprecationWarning, stacklevel=2)
return self.is_alive()
@property
def daemon(self):
assert self._initialized, "Thread.__init__() not called"
return self._daemonic
@daemon.setter
def daemon(self, daemonic):
if not self._initialized:
raise RuntimeError("Thread.__init__() not called")
if self._started.is_set():
raise RuntimeError("cannot set daemon status of active thread")
self._daemonic = daemonic
接下來介紹一下方法:
start():啟動線程,並調用該子線程中的run()
run(): 線程啟動時運行的方法,正是它去調用target指定的函數,我們自定義類的類中一定要實現該方法
is_alive():如果p仍然運行,返回True
join([timeout]):主線程等待p終止(強調:是主線程處於等的狀態,而p是處於運行的狀態)
timeout是可選的超時時間
Thread的使用
首先很重要的一點就是,在windows系統,線程的開啟必須放到if name == 'main':的下面
第一種方法
from threading import Thread
def func(name, *args, **kwargs):
print(f'{name}執行!')
pass
if __name__ == '__main__':
p = Thread(target=func, args=('子線程',))
p.start()
print('我是主線程... ...')
在主進程中創建一個子進程,用來執行函數func,並對函數進行傳參
然后利用start進行聲明子進程
第二種方法
from threading import Thread
class Mythread(Thread):
"""這是Mythread"""
def __init__(self, name):
super().__init__()
self.name = name
def run(self):
print(f'{self.name}執行!')
if __name__ == '__main__':
p = Mythread('子線程')
p.start()
print('我是主線程... ...')
這種方法用的太少了,就看一下了解一下就行
更多的還是第一種方法的使用