标签:__ range start Pytorch time print main 推理 cpu
目标:pytorch不管是训练还是推理时。cpu的使用率基本只有10%左右,尝试更好的利用cpu来加快训练和推理。
1.在搜索资料时很多作者都提到了python的GIL问题,这边先了解下这个机制直接从例子入手。
本机的cpu是i5-4460 4核4线程
先参考涤生手记的清晰讲述,本实验用的是python3.5故修改下代码。( Python 3.2开始使用新的GIL。在新的GIL实现中其他线程请求这个锁的时候,当前线程就会在5ms后被强制释放掉这个锁。)
GIL锁的释放机制:
Python解释器进程内的多线程是合作多任务方式执行。当一个线程遇到I/O任务时,将释放GIL。计算密集型(CPU-bound)的线程在执行大约100次解释器的计步(ticks)时,将释放GIL。计步(ticks)可粗略看作Python虚拟机的指令。计步实际上与时间片长度无关。可以通过sys.setcheckinterval()设置计步长度。
A1.单线程执行同一个程序调用,耗时71.47s
import time
def counter1():
for i in range(300000000):
i = i + 1
print("this is i:", i + 5)
def counter2():
for j in range(300000000):
j = j + 1
print("this is j:", j + 10)
def main():
start_time = time.time()
for x in range(2):
counter2()
counter1()
end_time = time.time()
print("Total time: {}".format(end_time - start_time))
if __name__ == '__main__':
main()
this is j: 300000010
this is i: 300000005
this is j: 300000010
this is i: 300000005
Total time: 71.47001194953918
A2.多线程执行同一个程序,耗时72.08s。
from threading import Thread
import time
def counter1():
for i in range(300000000):
i = i + 1
print("this is i:", i + 5)
def counter2():
for j in range(300000000):
j = j + 1
print("this is j:", j + 10)
def main():
start_time = time.time()
for x in range(2):
t1 = Thread(target=counter2)
t2 = Thread(target=counter1)
t1.start()
t2.start()
t2.join()
end_time = time.time()
print("Total time: {}".format(end_time - start_time))
if __name__ == '__main__':
main()
this is i: 300000005
this is j: 300000010
this is i: 300000005
Total time: 72.07586812973022
this is j: 300000010
显然上面两个案例看出同一个程序,在python中 (Cpthon)单线程反而要比多线程执行的快,因为GIL锁的缘故,多线程实际上需要频繁切换进行并发操作,尤其对于多核CPU来说,存在严重的线程颠簸(thrashing)。
B1.同样使用单线程执行同一个程序,注意同样是上面的程序,这里在代码中增加了sleep(0.01)耗时操作。结果这个时候单线程 执行完程序耗时:42.10s.
import time
def counter1():
for i in range(1000):
i = i + 1
time.sleep(0.01)
print("this is i:", i + 5)
def counter2():
for j in range(1000):
j = j + 1
time.sleep(0.01)
print("this is j:", j + 10)
def main():
start_time = time.time()
for x in range(2):
counter2()
counter1()
end_time = time.time()
print("Total time: {}".format(end_time - start_time))
if __name__ == '__main__':
main()
this is j: 1010
this is i: 1005
this is j: 1010
this is i: 1005
Total time: 42.09901976585388
B2.同样使用多线程执行同一个程序,注意同样是上面的程序,这类在代码中增加了sleep(0.01)耗时操作。结果这个时候多线程 执行完程序耗时:22.00s。
from threading import Thread
import time
def counter1():
for i in range(1000):
i = i + 1
time.sleep(0.01)
print("this is i:", i + 5)
def counter2():
for j in range(1000):
j = j + 1
time.sleep(0.01)
print("this is j:", j + 10)
def main():
start_time = time.time()
for x in range(2):
t1 = Thread(target=counter1)
t2 = Thread(target=counter2)
t1.start()
t2.start()
t2.join()
end_time = time.time()
print("Total time: {}".format(end_time - start_time))
if __name__ == '__main__':
main()
this is j: 1010
this is i: 1005
this is i: 1005
this is j: 1010
Total time: 22.006017684936523
为什么同样一个程序,增加了sleep耗时操作以后在python中多线程的操作又比单线程执行的更快了呢?这不就和上面的结果矛盾了吗?这其实说到底就是GIL锁的释放机制了。如上:当一个线程遇到I/O任务时,将释放GIL。计算密集型(CPU-bound)的线程在执行大约100次解释器的计步(ticks)时,将释放GIL。所以说我们增加了sleep耗时操作,相当于将计算型的程序变成了耗时等待的I/O程序,这个时候GIL锁遇到I/O任务时,不会继续等待耗时操作,而是立马释放锁,给其他线程去执行,这样的话效率会比单线程高很多(因为单线程需要等待耗时结束才能继续执行)
标签:__,range,start,Pytorch,time,print,main,推理,cpu 来源: https://blog.csdn.net/qq_36401512/article/details/113105009
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。