如何并行化普通的python代码

本文探讨了使用Taichi和Python进行并行计算的方法,包括Monte Carlo方法计算π值及其实现优化,对比了不同实现方式的性能差异。

进程,不会;GIL锁。

taichi呢?试试吧,也不大会。

就用这个里面的例子来当靶子

练一练

例1

蒙特卡洛计算pi的代码

用一行代码实现python多进程加速_哔哩哔哩_bilibili

 

原理图,引用自:(69条消息) 蒙特卡洛方法计算圆周率_tiansch的博客-优快云博客_蒙特卡洛求圆周率

虽然random只取【0,1】,但是也没毛病……比例关系还是一样的。

python怎么计算时间

(69条消息) python:计算程序运行时间_Caesar6666的博客-优快云博客_python计算程序运行时间

代码

import taichi as ti
import random
import time
ti.init(arch=ti.gpu)

N=1_0000_0000

#对了,蒙特卡洛算Π,用这个来当靶子好了

@ti.kernel
def calc_pai()->ti.f32:
    t=0.0
    for _ in range(N):
        x=ti.random()
        y=ti.random()
        if x**2+y**2<=1:
            t+=1#加锁的
    return t/N*4

def calc_pai_normal()->float:
    t=0.0
    for _ in range(N):
        x=random.random()
        y=random.random()
        if x**2+y**2<=1:
            t+=1#加锁的
    return t/N*4

start=time.time()
print(calc_pai())
end=time.time()
print("运行时间是",end-start)

start=time.time()
print(calc_pai_normal())
end=time.time()
print("运行时间是",end-start)

结果 

 如果会写,看来还是有加速的效果的……就怕不会写。

更复杂的,该怎么做?

例2

多文件的怎么搞?哪有那么多单文件的程序?

首先,python的多文件编程是怎么搞的?

python多文件编程

先搞个正常的普通的串行的:

头文件
/////////////////////////////////////////////////////
class calc:
    def __init__(self,data_x,data_y) -> None:
        self.data_x=data_x
        self.data_y=data_y
        pass
    def calc_pi(self)->float:
        t=0
        for i in range(len(self.data_x)):
            if self.data_x[i]**2+self.data_y[i]**2<=1:
                t+=1
        return t/len(self.data_x)*4

主函数
//////////////////////////////////////////////////////
import multi_file
import random
import time
N=100_0000
data_x,data_y=[],[]
for i in range(N):
    data_x.append(random.random())
    data_y.append(random.random())

test=multi_file.calc(data_x,data_y)

start=time.time()
print(test.calc_pi())
end=time.time()
print("运行时间是",end-start,"秒")

 引入taichi

类+taichi,怎么写的?

怎么把俩list放到taichi函数里的形参上去?

列表?ti.field?

百度启动:(69条消息) 基于python与CUDA的N卡GPU并行程序——taichi语言笔记_遂古之初,谁传道之的博客-优快云博客_python taichi

numpy转ti。field?

也不一定要传吧,搞个全局变量?失败……

////////////////////////////////////////
import taichi as ti
ti.init(arch=ti.gpu)

DATA_X,DATA_Y=[],[]

@ti.kernel
def calc_pi_parr()->float:
    t=0
    for i in range(len(DATA_X)):
        if DATA_X[i]**2+DATA_Y[i]**2<=1:
            t+=1
    return t/1000000*4  



class calc:
    def __init__(self,data_x,data_y) -> None:
        self.data_x=data_x
        self.data_y=data_y
        pass
    def calc_pi(self)->float:
        t=0
        for i in range(len(self.data_x)):
            if self.data_x[i]**2+self.data_y[i]**2<=1:
                t+=1
        return t/len(self.data_x)*4

    def calc_pi_2(self)->float:
        result=calc_pi_parr()
        return result



///////////////////////////////////////
import multi_file
import random
import time
N=100_0000
data_x,data_y=[],[]
for i in range(N):
    data_x.append(random.random())
    data_y.append(random.random())

multi_file.DATA_X,multi_file.DATA_Y=data_x,data_y


test=multi_file.calc(data_x,data_y)

start=time.time()
print(test.calc_pi())
end=time.time()
print("运行时间是",end-start,"秒")

start=time.time()
print(test.calc_pi_2())
end=time.time()
print("运行时间是",end-start,"秒")

 

 

这个里面说的——ti.kernel,参数只能是标量,返回值也只能是标量……

 所以,就用ti.field,然后用ti.kernel调用ti.func

试试吧……

先声明个field变量,它的形参都是什么意思啊啊?

自带网页,这么高级的吗……

Fields | Taichi Docs (taichi-lang.org)

 声明个1D的就行了,那末,怎么给它赋值?

文档里有……

 这个ti.field,怎么传参?它好像是个全局变量,不需要传参。

然后,怎么遍历它?

 接着找文档……

 不好搞,它这个field,大小好像得是提前设置完的。

要不,不是调用taichi函数,而是调用taichi类?

它会把python的变量编译成常量……多次使用的时候搞不好会GG。

代码写成了这样,也可以正常运行了,但是,并行比串行还慢,GPU利用率还高的吓人……这种情况,之前是见过的……可能是因为它要拷贝一个巨大的数组?

代码记录一下吧,再次失败……

////////////////////////////////////////////////
import taichi as ti
ti.init(arch=ti.gpu)

@ti.data_oriented
class calc_parr:
    def __init__(self,data_x,data_y) -> None:
        #声明
        self.DATA_X=ti.field(ti.float32,shape=len(data_x))
        self.DATA_Y=ti.field(ti.float32,shape=len(data_y)) 
        #赋值
        for index,value in enumerate(data_x):
            self.DATA_X[index]=value
        for index,value in enumerate(data_y):
            self.DATA_Y[index]=value
        pass

    @ti.kernel
    def calc_pi(self)->float:
        t=0
        for i in range(self.DATA_X.shape[0]):#是方括号不是圆括号不然会报错
            if self.DATA_X[i]**2+self.DATA_Y[i]**2<=1:
                t+=1
        return t/self.DATA_X.shape[0]*4  



class calc:
    def __init__(self,data_x,data_y) -> None:
        self.data_x=data_x
        self.data_y=data_y
        pass
    def calc_pi(self)->float:
        t=0
        for i in range(len(self.data_x)):
            if self.data_x[i]**2+self.data_y[i]**2<=1:
                t+=1
        return t/len(self.data_x)*4


////////////////////////////////////////////////////////////////
import multi_file
import random
import time
N=100_0000
data_x,data_y=[],[]
for i in range(N):
    data_x.append(random.random())
    data_y.append(random.random())


test=multi_file.calc(data_x,data_y)

start=time.time()
print(test.calc_pi())
end=time.time()
print("运行时间是",end-start,"秒")

test=multi_file.calc_parr(data_x,data_y)
start=time.time()
print(test.calc_pi())
end=time.time()
print("运行时间是",end-start,"秒")

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值