''' Python由于全局解释器锁(GIL)的存在,多线程并不能发挥多核的性能。 实际上,即使使用多线程,每时刻运行的只是一个线程,因为只有线程获得GIL锁才可以运行。 在某一线程运行100条字节码或者进入IO操作的时候,会释放GIL,切入另一个线程。 因此,为了发挥多核的性能,我们使用多进程的方式,Pythond的标准库中,有跨平台的 多进程模块multiprocessing。 下面介绍,multiprocessing的使用 ''' import os, time import multiprocessing ''' multiprocessing中的Process类用来创建进程对象,需要指定运行的函数, 函数的输入值, Process(target = func_name, args = input_args) args要使用元组的形式,即使有一个参数a,也要写成args = (a, )的形式。 下面是创建两个进程的例子 ''' # 例子1 def job01(n): print("Current Process is at PID({}), input is {}.".format(os.getpid(), n)) # os.getpid()获得当前运行的进程的进程号PID x = 0 for i in range(n): x += i**3 print("Result is {}.".format(x)) return x def main01(): p1 = multiprocessing.Process(target = job01, args = (10, )) p2 = multiprocessing.Process(target = job01, args = (110, )) p1.start() p2.start() # 如果运行这个例子,取消下面注释 ''' if __name__ == "__main__": main01() ''' # join的作用 ''' 当p1, p2 start之后,总共有3个进程,p1, p2和主进程 如果p2.start()语句之后还有一句,print("All done.") 看例子2 其中,为了更明显看出问题,使得job运行时间更长,添加了一句 time.sleep(10) #当前进程所在的核,停止10秒 例子2的运行结果如下, All done. Current Process is at PID(10756), input is 110. Current Process is at PID(6224), input is 10. Result is 35940025. Result is 2025. 很奇怪,为什么,先输出了"All done." 明明把print("All done.")放在了p1.start(),p2.start()后面。 因为,start只是开始启动进程,一旦启动,就继续执行后面的语句了, 不在理会p1和p2是在干什么,由于p1和p2运行时间长, 所以,print("All done.")之后才运行完p1,p2 但是这和程序逻辑不符。 所以,在要在p1.start()后面加上一句 p1.join() 表示只有p1执行结束,才会继续执行主进程后面的语句。 修改后,参看例子3 ''' # 例子2 def job02(n): print("Current Process is at PID({}), input is {}.".format(os.getpid(), n)) # os.getpid()获得当前运行的进程的进程号PID time.sleep(10) x = 0 for i in range(n): x += i**3 print("Result is {}.".format(x)) return x def main02(): p1 = multiprocessing.Process(target = job01, args = (10, )) p2 = multiprocessing.Process(target = job01, args = (110, )) p1.start() p2.start() print("All done.") # 如果运行这个例子,取消下面注释 ''' if __name__ == "__main__": main02() ''' # 例子3 def main03(): p1 = multiprocessing.Process(target = job01, args = (10, )) p2 = multiprocessing.Process(target = job01, args = (110, )) p1.start() p1.join() p2.start() p2.join() print("All done.") # 如果运行这个例子,取消下面注释 ''' if __name__ == "__main__": main03() ''' ''' 例子3执行结果如下: Current Process is at PID(500), input is 10. Result is 2025. Current Process is at PID(14064), input is 110. Result is 35940025. All done. 和我们的逻辑一样。 All done. 在最后输出。 '''
# 进程池 Pool 的使用 ''' 每次用一个Process有些麻烦,当我们需要多个进程,只是输入不同,有没有简单的方法呢。 答案使用Pool,例子4 ''' import os, time import multiprocessing from multiprocessing import Process, Pool def job01(n): print("Current Process is {} at PID({})." .format(multiprocessing.current_process().name, os.getpid())) x = 0 for i in range(n): x += i**4 print("Result: {}".format(x)) if n == 3: time.sleep(5) return x def main(): print(multiprocessing.current_process().name) nums = [1, 3, 8, 110] pool = Pool(processes = 3) print(pool.map(job01, nums)) if __name__ == "__main__": main() ''' multiprocessing.current_process().name 获得当前进程的名称 实际上,设置一个进程的时候,是可以指定名称的。比如, p = Process(target = job, args = input, name = "Hello") 主进程的名字是 "MainProcess" Pool(processes = 4)设置进程的数目 默认是机器的逻辑处理器数目,8核16线程的cpu,默认是16。 可以,通过multiprocessing.cpu_count()得到这个数目 如果,我设置为3会怎么样? 有4个输入! 会只有三个进程,只有一个进程结束后,才会输入第4个数,开启新的进程。 但是,同时最多3个进程。 这里,我故意将n=3的情况,sleep(5)使他的运行时间最长, 但是我们发现,输出还是按照输入的顺序。 '''
#