Python多服务器、多CPU、多核并行计算学习笔记

这篇博客通过Python实现蒙特卡罗方法计算圆周率,对比了普通模式、多线程和多进程模式在不同点数计算下的性能。测试结果显示,线程数对计算时间影响不大,而进程数显著影响效率。Python的线程由于GIL限制并不适合计算密集型任务,多进程更适合。作者还提到未来可能探索dask和ray等工具。
摘要由CSDN通过智能技术生成

       近来接触一超算小集群,那咱用起来就不能和在单机上一样了,要充分发挥其高性能、集群的优势。故以Python程序为例,研究调用多核多CPU甚至多服务器进行并行计算的问题,留下此笔记。

       本次学习以蒙特卡罗方法计算圆周率的小程序来做基础,测试它在普通模式下、调用多线程模式下、调用多进程模式下运行所需的时间。测试平台是在集群内的一点节点,即其中的一台服务器,硬件配置为8颗Intel Xeon 8260 2.4GHz/24c,操作系统CentOS Linux release 7.5.1804 (Core) ,python版本为3.9.12。(如果,我说是如果,如果我把这机器搬回家看看电影、玩玩挖雷…………)

        先列出程序源代码。

 一、普通模式

        很多python教程上都有的一个小程序,在普通电脑上可以很容易调试成功。分别测试了300‘000、3‘000’000、30‘000’000、300‘000’000个点。

#用蒙特卡罗方法计算圆周率,思路是在图形中随机抛置大量的点, 计算落在1/4圆内的点的数量。
import random
import time

n = 300000000  #点的个数,点越多PI越精确,计算量越大、时间越长。
old_time = time.time()   #记录开始时间

def monte_carlo_pi_part(n):
    count=0
    for i in range(n):
        x = random.random()    #随机生成的一个实数,它在[0,1)范围内。
        y = random.random()
        if x * x + y* y <=1:    #如果点(x,y)离坐标系原点的距离小于等于1,计数一次。
            count +=1            
    return count

if __name__ ==  '__main__':
    print('Run across normal state')    
    count = monte_carlo_pi_part(n)
    print('Estimated value of Pi:: ', count / (n * 1) * 4)
    current_time = time.time()  #记录结束时间
    print("time is " + str(current_time - old_time) + "s")#输出程序运行时间

二、多线程模式

        因采用多线程(m个),故将计算任务进行分割,每个线程算一部分点(n/m个)。最后将每个线程统计的落入圆内的点数求和,再算出PI。

        测试了30‘000’000点/5线程、30‘000’000点/10线程、300‘000’000点/1线程、300‘000’000点/5线程、300‘000’000点/10线程。

# 运用蒙特卡罗方法计算圆周率,思路是在图形中随机抛置大量的点, 计算落在1/4圆内的点的数量。
# 测试多线程,每个线程各计算n/m个点。
import random
import time
from concurrent.futures import ThreadPoolExecutor

n = 30000000  #点的个数,点越多PI越精确,计算量越大、时间越长。
m = 2        #线程数
results = []

def monte_carlo_pi_part(n):
    count=0
    for i in range(n):
        x = random.random()    #随机生成的一个实数,它在[0,1)范围内。
        y = random.random()
        if x * x + y* y <=1:    #如果点(x,y)离坐标系原点的距离 小于等于1,计数一次。
            count +=1
    return count

def run_mainthread():
    pool = ThreadPoolExecutor(max_workers=m)  # 创建一个包含m条线程的线程池

    for i in range(m):
        Thr = pool.submit(monte_carlo_pi_part,int(n/m))  # submit异步提交任务
        results.append(Thr)
    pool.shutdown()

if __name__ == '__main__':
    s = 0
    print('Run across ' + str(m) + ' thread')
    old_time = time.time()   #记录开始时间
    run_mainthread()

    for res in results:
        s = s + res.result()

    print('Estimated value of Pi:: ', s/n*4)
    current_time = time.time()  #记录结束时间
    print("time is " + str(current_time - old_time) + "s")#输出程序运行时间

三、多进程模式

        同样是蒙特卡罗方法计算圆周率的小程序,但是程序调用了m个进程来运行,每个进程来计算n/m个点,最后将每个进程统计的落入圆内的点数求和,再算出PI。

        测试了300‘000’000点/1进程、300‘000’000点/10进程、300‘000’000点/100进程、3‘000‘000’000点/10进程、3’000‘000’000点/100进程、

# 运用蒙特卡罗方法计算圆周率,思路是在图形中随机抛置大量的点, 计算落在1/4圆内的点的数量。
# 测试多进程,每个进程各计算n/m个点。
import random
import time
from multiprocessing import  Pool

results = []
n = 300000000 #点的个数,点越多PI越精确,计算量越大、时间越长。
m = 1        #电脑的CPU核数
def monte_carlo_pi_part(n):
    count=0
    for i in range(n):
        x = random.random()     #随机生成的一个实数,它在[0,1)范围内。
        y = random.random()
        if x * x + y* y <=1:    #如果点(x,y)离坐标系原点的距离小于等于1,计数一次。
            count +=1            
    return count

def run_mainprocess(): 
    pool = Pool(processes=m)    #引入进程池,设m个进程。
    for i in range(m):
        result = pool.apply_async(monte_carlo_pi_part,(int(n/m),)) #每个进程各计算n/m个点
        results.append(result) 
    pool.close()
    pool.join()

if __name__ == '__main__':
    s = 0
    print('Run across ' + str(m) + ' Process')
    old_time = time.time()   #记录开始时间    
    run_mainprocess()        
    for res in results:
        s = s + res.get() 
    print('Estimated value of Pi:: ', s/n * 4)
    current_time = time.time()  #记录结束时间
    print("node="+str(n)+"\nprocess="+str(m)+"\ntime is " + str(current_time - old_time) + "s")#输出程序运行时间

四、测试结果        

计算的点数

普通

模式

线程数进程数
1510110100
300‘0000.0805
3’000‘0000.7159
30’000‘0007.47177.68307.3803
300’000‘00074.971874.610776.440874.172175.91727.83111.2749
3’000‘000’00077.2348.4092

                                注:表格中的小数为程序运算所需的时间。

        结论:从表中可看出线程数的多少,对计算时间没有影响,而进程数的多少却有显著的不同。Python的线程是伪线程,由于GIL的限制,同时只能有一个线程运行,这不适合计算密集型任务,只能应用于IO密集型任。不过调用多进程要将计算任务进行分割,调整程序设计。

        笔记到此告一段落,多台服务器没找到方法,哎!学习累啊!

        听说有dask、ray……

        那又是什么?

        下次笔记吧!……

        后话,当我测试100个cpu核心时,服务器的散热风扇开始暴力运行,发出刺耳的声音,一度我认为要出问题了,多亏时间短,计算完了,风扇的转速也就降下来了。这带回家…………

        下次我测了个时间长点的计算任务,测一下风扇的性能…………嘿嘿!

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值