目录
进程和线程
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())
来源: https://www.cnblogs.com/dianel/p/10477819.html