一:为什么
进程(process)和线程(thread)是非常抽象的两个概念,但也是一位python程序员必不可少的技能。尤其在进行cpu大数据计算时,就是一个非常好的加速方式。
二:基础知识
1.线程:线程是一个基本的CPU执行单元,它可以和统一进程下的其他线程共享全部资源。
2.进程:进程是指一个程序在给定数据集合上的一次执行过程,是系统进行资源分配和运行调用的独立单位。每个进程都有自己的地址空间。也就是说一个应用程序至少包括1个进程,而1个进程包括1个或多个线程。
3.线程的类型:
线程按照作用可大致划分为:
主线程
子线程
后台线程
前台线程
三:python多线程
注意:现在的cpu都是多核cpu,是支持多个线程同时执行的,但是python同时只能有一个线程在执行。
其主要原因是GIL的存在,每次释放 GIL锁,线程进行锁竞争、切换线程,会消耗资源。这就导致打印线程执行时长,会发现耗时更长的原因。
1.创建多线程
Python提供了threading模块。
thread.Thread() | 函数需要接受两个参数,第一个是target,一般指要调用的函数名,第二个args,表示需要向函数中传递的参数。 |
start() | 开启多线程。 |
threading.current_thread().name | 打印出当前线程的名字。 |
threading.enumerate() | 返回一个包含正在运行的线程的list |
import threading
def test1():
print(threading.current_thread().name)
def test2():
print(threading.current_thread().name)
print(threading.current_thread().name)#可以打印出当前线程的名字
print(threading.enumerate())#返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
thread1 = threading.Thread(target=test1,name="thread1")
thread2 = threading.Thread(target=test2,name="thread2")
thread1.start()
thread2.start()#把线程开起来
结果
2.线程等待
当我们子线程还在运行时,但是主线程已经在往下运行。主线程结束后,子线程还在运行,join函数使得主线程等到子线程结束后再往下运行。
import time
import threading
def test1():
print(threading.current_thread().name)
time.sleep(2)
print("thread1end")
def test2():
print(threading.current_thread().name)
time.sleep(5)
print("thread2end")
print(threading.current_thread().name)#可以打印出当前线程的名字
print(threading.enumerate())#返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
thread1 = threading.Thread(target=test1,name="thread1")
thread2 = threading.Thread(target=test2,name="thread2")
thread1.start()
thread2.start()#把线程开起来
print("*********")
结果:
加入等待join()
import time
import threading
def test1():
print(threading.current_thread().name)
time.sleep(2)
print("thread1end")
def test2():
print(threading.current_thread().name)
time.sleep(5)
print("thread2end")
print(threading.current_thread().name)#可以打印出当前线程的名字
print(threading.enumerate())#返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
thread1 = threading.Thread(target=test1,name="thread1")
thread2 = threading.Thread(target=test2,name="thread2")
thread1.start()
thread2.start()#把线程开起来
thread2.join()
thread1.join()#等上面的线程都运行完了,再运行下面的代码
print("*********")
结果:
3.数据传输
利用Queue实现不同线程间的沟通,它主要有两个函数,put和get。put() 用以插入数据到队列中,get()可以从队列读取并且删除一个元素。
import time
import threading
from queue import Queue
def test1(q):
print(threading.current_thread().name)
time.sleep(2)
print("thread1end")
q.put([1,2,3])
def test2(q):
print(threading.current_thread().name)
time.sleep(5)
print("thread2end")
q.put([4,5,6])
print(threading.current_thread().name)#可以打印出当前线程的名字
print(threading.enumerate())#返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
qq=Queue()
thread1 = threading.Thread(target=test1,name="thread1",args=(qq,))
thread2 = threading.Thread(target=test2,name="thread2",args=(qq,))
thread1.start()
thread2.start()#把线程开起来
thread2.join()
thread1.join()#等上面的线程都运行完了,再运行下面的代码
print("*********")
print(qq.get())
print(qq.get())
结果:
四:python多进程
利用multiprocess模块创建多进程,其中有两种创建方式。
1.方式一
利用Pool类,Pool类可以提供指定数量的进程供用户调用,当有新的请求提交到Pool中时,如果进程池还没有满,就会创建一个新的进程来执行请求。如果池满,请求就会告知先等待,直到池中有进程结束,才会创建新的进程来执行这些请求。
Pool常用方法如下:
apply() | 同步执行(串行) |
apply_aspnc() | 异步执行(并行) |
terminate() | 立刻关闭进程池 |
join() | 主进程等待所有子进程执行完毕 |
close() | 等待所有进程结束后,才关闭进程池 |
import multiprocessing
import time
def test1(q,):
print("test1")
q.put(1)
def test2(q,):
time.sleep(0.5)
print("test2")
q.put(2)
if __name__=="__main__":
q=multiprocessing.Queue()
q2=multiprocessing.Queue()
pool=multiprocessing.Pool(3)
pool.apply_async(test1,args=(q,))
pool.apply_async(test1,args=(q2,))
pool.close()#join之前要调用close
pool.join()
2.方式二
直接使用Process实现多进程,其中也要利用Queue来完成各进程的沟通。
import multiprocessing
import time
def test1(q):
print("test1")
q.put([1,2,3])
def test2(q,):
time.sleep(0.5)
print("test2")
q.put([2])
if __name__ == '__main__':
qq=multiprocessing.Queue()
qq2=multiprocessing.Queue()
pro=multiprocessing.Process(target=test1,args=(qq,))
pro2 = multiprocessing.Process(target=test2, args=(qq2,))
pro.start()
pro2.start()
pro2.join()
pro.join()
print(qq.get())
print(qq2.get())
结果:
五:总结(多线程与多进程选择?)
本文总结了python的多线程与多进程的区别,并且详细介绍了threading与multiprocess模块进行多线程和多进程的编程。
对于CPU密集型代码(如循环)-使用多进程
对于IO密集型代码(如文件操作,网络爬虫)-多线程效率更高。
六:参考:
https://www.huaweicloud.com/articles/8c1da1adad72034695b4e40fe7501063.html
https://www.jianshu.com/p/a69dec87e646
公众号:柯西的笔,欢迎大家关注,时不时更新深度学习,机器学习,医学算法。