概念
1.线程执行处于alive
状态
2.线程A 可以调用线程B 的 join() 方法,调用后线程A 会被挂起,直到线程B 结束。
3.Python 程序的初始线程叫做“main thread”
class threading.Thread(group=None,target=None,name=None,args=(),kwargs={},*,daemon=None)
构造参数 | 描述 |
---|---|
group | 这参数是为将来可能出现的 ThreadGroup 类准备的(现在还没有实现) |
target | 要调用的函数 |
name | 本线程的名字,默认会分配一个形如“Thread-N”的名字 |
args | target的位置参数 |
kwargs | target的关键字参数 |
daemon | 默认为None |
对象方法属性 | 描述 |
---|---|
start() | 线程的执行,会在独立线程中执行run 方法 |
run() | |
join(timeout=None) | 调用join 的线程会一直阻塞调用者的线程,知道自己结束 |
timeout | |
name | 不同的进程name可以相同,可以通过getName() / setName() |
ident | “thread identifier”,如果线程还未开始,则为None,新的进程开始时,id可能被收回 |
is_alive() | |
daemon | 在start之前调用,默认False,只剩下"daemon thread“为alive状态时,整个程序会退出,可通过isDaemon() / setDaemon()访问 |
应用
1.线程传参
通过args
和kwargs
传参
from threading import Thread
def func(name,age):
print("子进程",name,age)
if __name__ == '__main__':
t = Thread(target=func, args=('wang',),kwargs={"age":10})
t.start()
2.获得线程程执行结果
1)手动Thread
创建子线程无法获得执行的结果
2)使用ThreadPoolExecutor
可以
from concurrent.futures import ThreadPoolExecutor
def func(p):
return p*p
if __name__ == "__main__":
r_lst = []
tp = ThreadPoolExecutor(5)
for i in range(10):
ret = tp.submit(func, i)
r_lst.append(ret)
tp.shutdown() # 阻塞,就有线程池完成任务才继续向下执行
[print(ret.result()) for ret in r_lst]
- 不通过
return
获得子进程返回结果,而是通过更改共享变量
3.线程同步-join
线程调用join()
方法让主线程等待线程的结束
from threading import Thread
import time
def func(name):
time.sleep(1)
print('子线程结束')
if __name__ == '__main__':
p = Thread(target=func, args=('wang',))
p.start()
# p.join() #子线程加上join后,主线程会阻塞直到该子线程结束
print("主线程结束")
4.父子线程关系-daemon
父线程结束后,子线程立刻结束,所以没有打印子线程结束
import time
from threading import Thread
def func(name):
time.sleep(1)
print('子线程结束')
if __name__ == '__main__':
t = Thread(target=func, args=('xiaobai',))
t.daemon = True
t.start()
print("主线程结束")
5.创建多个线程
1)手工循环创建
用列表保存每个子线程对象
当然子线程也可以使用join
来让主进程等待
import time
from threading import Thread
def func(name):
print("线程 %d执行" % name )
time.sleep(0.1)
if __name__ == '__main__':
t_lst = []
for i in range(10):
t = Thread(target=func, args=(i,))
t.start()
t_lst.append(p)
print("父线程结束")
2)使用线程池
首先,创建进程需要消耗时间,销毁进程(空间,变量,文件信息等等的内容)也需要消耗时间。
定义一个池子,在里面放上固定数量的进程,有需求来了,就拿一个池中的进程来处理任务,等到处理完毕,进程并不关闭,而是将进程再放回进程池中继续等待任务。
不会增加操作系统的调度难度,还节省了开闭进程的时间,也一定程度上能够实现并发效果。
参考:
https://www.cnblogs.com/Frank0128/p/10730817.html
https://my.oschina.net/lionets/blog/194577