进击の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('我是主线程... ...')
这种方法用的太少了,就看一下了解一下就行
更多的还是第一种方法的使用