Python 中的线程-进程2
原文:https://www.cnblogs.com/i-honey/p/7823587.html
Python中实现多线程需要使用到 threading 库,其中每一个 Thread类 的实例控制一个线程。
Thread类
#类签名
1
2
|
def __init__( self , group = None , target = None , name = None , args = (), kwargs = None , * , daemon = None ): |
简单介绍一些初始化参数:
target: 指定线程由 run () 方法调用的可调用对象。默认为 None, 意味着不调用任何内容。
name: 指定该线程的名称。 在默认情况下,创建一个唯一的名称。
args: target调用的实参,元组格式。默认为 (),即不传参。
daemon: 为False表示父线程在运行结束时需要等待子线程结束才能结束程序,为True则表示父线程在运行结束时,子线程无论是否还有任务未完成都会跟随父进程退出,结束程序。
线程启动:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import threading def worker(arg): #线程执行的目标函数 print ( "I'm working {}" . format (arg)) print ( "Fineshed" ) t = threading.Thread(target = worker,args = (threading.current_thread(),),name = "firstworker" ) #线程对象 t.start() #启动线程 运行结果: I'm working <_MainThread(MainThread, started 10936 )> Fineshed |
上面例子中,当函数执行完之后,线程也就跟着退出了。
线程的传参:
1
2
3
4
5
6
7
8
9
10
11
12
|
import threading def add(x,y): print (x + y) t = threading.Thread(target = add,args = ( 4 , 5 )) t.start() print ( "====end===" ) 运行结果: 9 = = = = end = = = |
线程的传参和函数传参没有区别,只需要注意传入的必须为元祖格式。
线程退出:
如果线程中任务是无限循环语句,那这个线程将无法自动停止。
Python线程退出条件有以下几种:
1、线程内的函数语句执行完毕,线程自动结束
2、线程内的函数抛出未处理的异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import threading import time def worker(arg): while True : time.sleep( 1 ) print ( "I'm working {}" . format (arg)) print ( "Fineshed" ) t = threading.Thread(target = worker,args = (threading.current_thread(),),name = "firstworker" ) t.start() 运行结果: I'm working <_MainThread(MainThread, stopped 2468 )> I'm working <_MainThread(MainThread, stopped 2468 )> I'm working <_MainThread(MainThread, stopped 2468 )> ... |
上面例子中,线程启动后,将一直循环下去,线程不会自动退出。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
import threading import time def worker(arg): count = 0 while True : if count > 5 : raise RuntimeError(count) time.sleep( 1 ) print ( "I'm working {}" . format (arg)) count + = 1 print ( "Fineshed" ) t = threading.Thread(target = worker,args = (threading. enumerate (),)) t.start() print ( "====end===" ) 运行结果: = = = = end = = = I'm working [<_MainThread(MainThread, stopped 10992 )>] I'm working [<_MainThread(MainThread, stopped 10992 )>] I'm working [<_MainThread(MainThread, stopped 10992 )>] I'm working [<_MainThread(MainThread, stopped 10992 )>] I'm working [<_MainThread(MainThread, stopped 10992 )>] I'm working [<_MainThread(MainThread, stopped 10992 )>] Exception in thread Thread - 1 : Traceback (most recent call last): File "C:/python/test.py" , line 8 , in worker raise RuntimeError(count) RuntimeError: 6 |
上面例子中,演示了触发异常自动退出线程。但最先打印的是主程序的"===end==="语句,是因为在程序中,主线程启动一个线程后,不会等待子线程执行完毕,就继续执行了后续语句,在执行完主线程语句后,发现还有子线程没有结束,于是等待子线程执行结束,子线程在运行时抛出了未处理的异常,最终子线程结束,主线程也随之结束。这里需要了解daemon线程和non-daemon线程,稍后就会介绍。
threading属性:
threading.current_thread() 返回当前线程对象
threading.main_thread() 返回主线程对象
threading.active_count() 返回处于Active状态的线程个数
threading.enumerate() 返回所有存活的线程的列表,不包括已经终止的线程和未启动的线程
threading.get_ident() 返回当前线程的ID,非0整数
举例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
import threading import time def showthreadinfo(): print ( "current thread = {}" . format (threading.current_thread())) print ( "main thread = {}" . format (threading.main_thread())) print ( "active thread count = {}" . format (threading.active_count())) print ( "active thread list = {}" . format (threading. enumerate ())) print ( "thread id = {}" . format (threading.get_ident())) print ( "~~~~~~~~~~~~~" ) def add(x,y): time.sleep( 1 ) showthreadinfo() #子线程中调用 print (x + y) showthreadinfo() #主线程中调用 time.sleep( 1 ) t = threading.Thread(target = add,args = ( 4 , 5 )) t.start() print ( "====end===" ) 运行结果: current thread = <_MainThread(MainThread, started 192 )> main thread = <_MainThread(MainThread, started 192 )> active thread count = 1 active thread list = [<_MainThread(MainThread, started 192 )>] thread id = 192 ~~~~~~~~~~~~~ = = = = end = = = current thread = <Thread(Thread - 1 , started 8424 )> main thread = <_MainThread(MainThread, stopped 192 )> active thread count = 2 active thread list = [<_MainThread(MainThread, stopped 192 )>, <Thread(Thread - 1 , started 8424 )>] thread id = 8424 ~~~~~~~~~~~~~ 9 |
上面例子中,在主线程中只能看到存活的只有自己,因为子线程还没有启动,且它的父线程就是它自己。子线程启动时,它的名字为Thread-1,这个名字是解释器自动命名的,如果定义线程对象时添加了name="threadName",则这里显示的就是threadName;同时,子线程的父线程就是主线程,也就是说谁启动的线程谁就是它的父线程;子线程能看到的存活线程有父线程和自身。
Thread实例的属性:
threading.current_thread().name 线程名,只是一个标识符,可以使用getName()、setName()获取和运行时重命名。
threading.current_thread().ident 线程ID,非0整数。线程启动后才会有ID,否则为None。线程退出,此ID依旧可以访问。此ID可以重复使用
threading.current_thread().is_alive() 返回线程是否存活,布尔值,True或False。
举例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
import threading import time def worker(): count = 1 while True : if count > = 6 : break time.sleep( 1 ) count + = 1 print ( "thread name = {}" . format (threading.current_thread().name)) t = threading.Thread(target = worker,name = "MyThread" ) t.start() while True : time.sleep( 1.1 ) if t.is_alive(): print ( "{} {} alive" . format (t.name,t.ident)) else : print ( "{} {} alive" . format (t.name, t.ident)) t.start() print ( "====end===" ) 运行结果: thread name = MyThread MyThread 9400 alive thread name = MyThread MyThread 9400 alive thread name = MyThread MyThread 9400 alive thread name = MyThread MyThread 9400 alive thread name = MyThread MyThread 9400 alive Traceback (most recent call last): File "C:/python/test.py" , line 22 , in <module> t.start() raise RuntimeError( "threads can only be started once" ) RuntimeError: threads can only be started once |
从上面例子中可以看到子线程存活时的名字和线程ID,但在线程退出后,尝试再次启动线程时,抛出RuntimeError异常,表明线程对象在定义后只能启动一次。
举例 getName()和setName():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
import threading import time def add(x,y): for _ in range ( 5 ): time.sleep( 1 ) print ( "x+y={}" . format (x + y)) t = threading.Thread(target = add,name = "MyThread" ,args = ( 6 , 7 )) t.start() while True : time.sleep( 1 ) if t.is_alive(): print ( "{} {} alive" . format (t.name,t.ident)) print ( "Thread name" ,t.getName()) t.setName( "MyThreadTwo" ) else : print ( "{} {} alive" . format (t.name, t.ident)) print ( "Thread abort...." ) break # t.start() print ( "====end===" ) 运行结果: MyThread 2564 alive Thread name MyThread x + y = 13 MyThreadTwo 2564 alive Thread name MyThreadTwo x + y = 13 MyThreadTwo 2564 alive Thread name MyThreadTwo x + y = 13 MyThreadTwo 2564 alive Thread name MyThreadTwo x + y = 13 MyThreadTwo 2564 alive Thread name MyThreadTwo x + y = 13 MyThreadTwo 2564 alive Thread abort.... = = = = end = = = |
上面例子演示了在运行时获取线程名和重命名线程名。
线程的start()和run()方法:
start():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
import threading import time def add(x,y): for _ in range ( 5 ): time.sleep( 0.5 ) print ( "x+y={}" . format (x + y)) class MyThread(threading.Thread): def start( self ): print ( 'start~~~~~~~~~~' ) super ().start() def run( self ): print ( 'run~~~~~~~~~~~~' ) super ().run() #调用父类的start()和run()方法 t = MyThread(target = add,name = "MyThread" ,args = ( 6 , 7 )) t.start() # t.run() print ( "====end===" ) 运行结果: start~~~~~~~~~~ run~~~~~~~~~~~~ = = = = end = = = x + y = 13 x + y = 13 x + y = 13 x + y = 13 x + y = 13 |
从上面的例子中,可以看出start()方法会先运行start()方法,再运行run()方法。
跟进一下start() 方法源码中的调用过程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
1 、 def start( self ): _start_new_thread( self ._bootstrap, ()) .... 2 、_start_new_thread = _thread.start_new_thread 3 、 def start_new_thread(function, args, kwargs = None ): pass 4 、 def _bootstrap( self ): self ._bootstrap_inner() 5 、 def _bootstrap_inner( self ): .... try : self .run() #最终start()方法调用了run()方法 except SystemExit: pass |
从上面跟踪源码的过程大概了解了start()方法如何调用到了run()方法。
run()方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
import threading import time def add(x,y): for _ in range ( 5 ): time.sleep( 0.5 ) print ( "x+y={}" . format (x + y)) class MyThread(threading.Thread): def start( self ): print ( 'start~~~~~~~~~~' ) super ().start() def run( self ): print ( 'run~~~~~~~~~~~~' ) super ().run() #调用父类的start()和run()方法 t = MyThread(target = add,name = "MyThread" ,args = ( 6 , 7 )) # t.start() t.run() print ( "====end===" ) 运行结果: run~~~~~~~~~~~~ x + y = 13 x + y = 13 x + y = 13 x + y = 13 x + y = 13 = = = = end = = = |
上面例子中,运行线程的run()方法只能调用到run()方法。
跟踪一下run() 方法在源码中的调用过程:
1
2
3
4
5
6
7
8
9
10
11
|
1 、 def __init__( self , group = None , target = None , name = None , args = (), kwargs = None , * , daemon = None ): self ._target = target self ._args = args self ._kwargs = kwargs .... 2 、 def run( self ): if self ._target: self ._target( * self ._args, * * self ._kwargs) .... |
可以看出,_target是我们传入的目标函数,run()方法其实就类似一个装饰器,最终还是将_args 和_kwargs 参数传入目标函数运行,返回结果。
start() --> run() --> _target()
run() --> _target()
上面两个例子简单介绍了start()方法和run()方法的调用,下一篇文章再详细看一下它们到底有什么区别。
总结:
本文主要介绍了: Thread类、线程启动、线程的传参、线程退出、threading属性、Thread实例的属性、举例getName()和setName()、线程的start()和run()方法
Python 中的线程-进程2的更多相关文章
- Python 中的线程-进程1
原文:https://www.cnblogs.com/i-honey/p/8042047.html 1. 并行和并发 并行:同时做某些事,可以互不干扰的同一时刻做几件事. 并发:也是同时做某些事,但是 ...
- Python中的线程和进程
引入进程和线程的概念及区别 threading模块提供的类: Thread, Lock, Rlock, Condition, [Bounded]Semaphore, Event, Timer, l ...
- python中的线程技术
#!/user/bin/env python # @Time :2018/7/7 11:42 # @Author :PGIDYSQ #@File :DaemonTest.py import threa ...
- 理解 Python 中的线程
原地址:http://blog.jobbole.com/52060/ 本文由 伯乐在线 - acmerfight 翻译自 Akshar Raaj.欢迎加入技术翻译小组.转载请参见文章末尾处的要求. 我 ...
- 【Python】解析Python中的线程与进程
基础知识 线程 进程 两者的区别 线程的类型 Python 多线程 GIL 创建多线程 线程合并 线程同步与互斥锁 可重入锁(递归锁) 守护线程 定时器 Python 多进程 创建多进程 多进程通信 ...
- Python之路-Python中的线程与进程
一.发展背景 任务调度 大部分操作系统(如Windows.Linux)的任务调度是采用时间片轮转的抢占式调度方式,也就是说一个任务执行一小段时间后强制暂停去执行下一个任务,每个任务轮流执行.任务执行的 ...
- 15.python并发编程(线程--进程--协程)
一.进程:1.定义:进程最小的资源单位,本质就是一个程序在一个数据集上的一次动态执行(运行)的过程2.组成:进程一般由程序,数据集,进程控制三部分组成:(1)程序:用来描述进程要完成哪些功能以及如何完 ...
- Python学习之==>线程&&进程
一.什么是线程(thread) 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一个线程指的是进程中一个单一顺序的控制流,一个进程中可以包含多个线程,每条线程并行 ...
- python中的线程锁
锁对象 原始锁是一个在锁定时不属于特定线程的同步基元组件.在Python中,它是能用的最低级的同步基元组件,由 _thread 扩展模块直接实现. 原始锁处于 "锁定" 或者 &q ...
随机推荐
- jQueryEasyUi行编辑打造增删改查
var $obj;$(function() { $obj = $("#configQueryGrid"); $obj.datagrid({ loadMsg : '数据加载中请稍后… ...
- A/libc:fatal signal 11(SIGSEGV).code 1, fault addr 0x0 in tid 26488 (VideoEncoder)
在调试Camera模块:发现相同的代码在厂家提供的环境里边编译.就是ok的,在我们的源码树中编译,将HAL库推进去后.就会signal 11退出. 一.现象 F/libc ( ): Fatal sig ...
- 如何打印Qt中的枚举所对应的字符串
比如,想获得socket的状态枚举文字, 代码如下: QMetaObject mo=QAbstractSocket::staticMetaObject; int index=mo.indexOfEnu ...
- 关于B/S和C/S模式
B/S注重的是 1.服务想玩游戏的时候,就出现想看电影的时候,就出现不用下载客户端太麻烦看个电影还要下载一大堆东西,不看了 2.维护升级软件不用一台一台地重新更新,百度一直在更新,但是我们感觉不到 3 ...
- 在windows下编译ffmpeg
编译ffmpeg,我在网上找了很多相关的方法,但最后都没编译成功. 所以下面就记录下自己的编译方法吧,留着以后编译的时候做参考. 1.首先,下载编译工具MinGW+Msys,搭建编译环境.工具下载地址 ...
- linux -- 查看Ubuntu命令行调用的文件
which 如: 输入:which reboot 输出:/sbin/reboot 输入:which shutdown -h now 输出:/sbin/shutdown
- Apache -- phpmyadmin导入文件过大
方法一: 找到php.ini(或php.ini-pre1.7.2)搜索这3个地方: upload_max_filesize memory_limit post_max_size 将他们后面的值修改成大 ...
- html -- <meta name="viewport"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scal ...
- 【Java面试题】46 描述一下JVM加载class文件的原理机制?
JVM中类的装载是由类加载器(ClassLoader)和它的子类来实现的,Java中的类加载器是一个重要的Java运行时系统组件,它负责在运行时查找和装入类文件中的类. 由于Java的跨平台性,经过 ...
- bootstrap table使用指南
Bootstrap table是国人开发的一款基于 Bootstrap 的 jQuery 表格插件,通过简单的设置,就可以拥有强大的单选.多选.排序.分页,以及编辑.导出.过滤(扩展)等等的功能. 目 ...