threading多线程模块
基本使用 Python中提供了 官方中文文档 实例化Therad类创建子线程 这种方式是最常用的也是推荐使用的方式。先来介绍一个
import threading time print("主线程任务开始处理") def task(th_name): 子线程任务开始处理,参数:{0}.format(th_name)) time.sleep(3) # <-- 这里睡眠了三秒,可以看见主线程继续往下走了 子线程任务处理完毕if __name__ == '__main__': ==== 实例化出Thread类并添加子线程任务以及参数 ==== t1 = threading.Thread(target=task,args=(线程[1]",)) <-- 参数必须添加逗号。因为是args所以会打散,如果不加逗号则不能进行打散会抛出异常 t1.start() 等待CPU调度..请注意这里不是立即执行 主线程任务处理完毕) ==== 执行结果 ==== """ 主线程任务开始处理 子线程任务开始处理,参数:线程[1] 主线程任务处理完毕 子线程任务处理完毕 """ 我们可以看见,在进行 图示: 自定义类继承Therad并覆写run方法 这种方法并不常见,但是还是要举例说出来。我们可以看到第一种方法是实例化出了
那么我们就可以自定义一个类并继承 class Threading(threading.Thread): 自定义类""" def __init__(self,th_name): self.th_name = th_name super(Threading,self).() run(self): .format(self.th_name)) time.sleep(3) <-- 这里睡眠了三秒,可以看见主线程继续往下走了 : t1 = Threading() t1.start() """ 注意现在依然是主线程任务处理完毕后现在是不会立马结束掉的,而是等子线程任务处理完毕后才会真正将主线程kill掉。其实原则上这两种创建线程的方式都一模一样。 源码浅析-选读 这个源码浅析非常浅,主要是来看一下基于实例化 那么我们看一下其
Thread: 注释被我删掉了""" _initialized = False 这是一个状态位,来表示该线程是否被被初始化过 __init__(self,group=None,target=None,name=None,args=(),kwargs=None,*,daemon=None): """ assert group is None,group argument must be None for now" 如果不是 None,daemon参数将显式地设置该线程是否为守护模式。 如果是 None (默认值),线程将继承当前线程的守护模式属性。 if kwargs is None: kwargs = {} kwargs 是用于调用目标函数的关键字参数字典。默认是 {}。 self._target = target 对于第一种调用方式来说,它就是我们的task函数。 self._name = str(name or _newname()) 线程名 self._args = args _args是用于调用目标函数的参数元组。默认是 ()。 self._kwargs = kwargs if daemon is not None: 判断其是否为守护线程 self._daemonic = daemon else: self._daemonic = current_thread().daemon self._ident = None 这个是线程的编号 if _HAVE_THREAD_NATIVE_ID: 判断是否具有本地ID self._native_id = None self._tstate_lock = None 锁定的状态 self._started = Event() 开始 self._is_stopped = False 状态位,是否停止 self._initialized = True 将初始化状态为改为True Copy of sys.stderr used by self._invoke_excepthook() self._stderr = _sys.stderr self._invoke_excepthook = _make_invoke_excepthook() For debugging and _after_fork() _dangling.add(self) 我们可以看见其 run(self): """ try: if self._target: 简单吧,这个方法,就是判断你有没有传入一个函数。即我们定义的task self._target(*self._args,**self._kwargs) 有的话就立即执行,我们传入的name其实就放在了_args中。这里将它打散出来了,所以我们的task函数中的第一个参数name能收到。 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 不管处不出错,都会清理他们。当然,如果有则是执行完成后清理 好了,其实看到这里就行了。其实我们自定义类的传参也可以不用覆写 主线程任务开始运行""" print(self._args) ('线程[1]',) print(self._kwargs) {} .format(self._args[0])) time.sleep(3) 子线程任务运行完毕) : t1 = Threading(args=(,)) t1.start() 等待CPU调度..请注意这里不是立即执行 主线程任务开始处理 ('线程[1]',) 主线程任务处理完毕 {} 子线程任务开始处理,参数:线程[1] 子线程任务处理完毕 """ threading模块方法大全
线程对象方法大全
常用方法示例由于方法太多了,所以这里就只例举一些非常常用的。 守护线程setDaemon()
我们对比上面的图,现在子线程是没有设置为守护线程的: 当他设置为守护线程之后会是这样的: 代码如下: .format(th_name)) time.sleep(3) : t1 = threading.Thread(target=task,)) t1.setDaemon(True) <-- 设置线程对象t1为守护线程,注意这一步一定要放在start之前。 t1.start() """ 线程阻塞join()
图示如下:(未设置超时时间) 代码如下: : t1 = threading.Thread(target=task,)) t1.start() 等待CPU调度..请注意这里不是立即执行 t1.join() <--- 放在start()下面,死等 ==== 执行结果 ==== """ 图示如下:(设置超时时间) 代码如下: t1.join(2) <--- 放在start()下面,等2秒后主线程继续执行 """ 注意, join()与setDaemon(True)共存
==== 情况一 ==== <--- 放在start()上面,主线程运行完后会立即终止子线程的运行。但是由于有join(),故不生效。 t1.start() """ ==== 情况二 ==== """ 设置与获取线程名我们来看一下如何设置与获取线程名。
.format(th_name)) obj = threading.current_thread() 获取当前线程对象 获取当前的线程名:{0}.format(obj.getName())) 开始设置线程名) obj.setName(yyy获取修改后的线程名:{0}.format(obj.getName())) time.sleep(3) : ==== 第一步:实例化出Thread类并添加子线程任务以及参数 ==== t1 = threading.Thread(target=task,),name=xxx") 可以在这里设置,如果不设置则为默认格式:Thread-1 数字是按照线程个数来定的 t1.start() 等待CPU调度..请注意这里不是立即执行 主线程名: 直接使用属性 name """ 多线程的应用场景 由于GIL锁的存在,Python中对于 注意:我们是在Python2版本下进行此次测试,Python3版本确实相差不大,但是,从本质上来说依然是这样的。 time num = 0 add(): global num for i in range(10000000): 一千万次 num += 1 sub(): in range(10000000): 一千万次 num -= 1 : start_time = time.time() add() sub() end_time = time.time() 执行时间: start_time) ==== 执行结果 ==== 三次采集 大约在 1.3 - 1.4 秒 """ coding:utf-8 time.time() t1 = threading.Thread(target=add,) t2 = threading.Thread(target=sub,) t1.start() t2.start() t1.join() t2.join() end_time =print(u start_time) 大约 4 - 5 秒 """ 补充:Timer线程延迟启动threading task(): print(threading.current_thread().getName(),end=""启动了...: t1 = threading.Timer(3 线程任务三秒后准备就绪,可以被CPU调度执行。 t2.start() Thread-1启动了... Thread-2启动了... """ (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |