如何并行化普通的python代码
进程,不会;GIL锁。
taichi呢?试试吧,也不大会。
就用这个里面的例子来当靶子
练一练
例1
蒙特卡洛计算pi的代码
用一行代码实现python多进程加速_哔哩哔哩_bilibili
原理图,引用自:(69条消息) 蒙特卡洛方法计算圆周率_tiansch的博客-CSDN博客_蒙特卡洛求圆周率
虽然random只取【0,1】,但是也没毛病……比例关系还是一样的。
python怎么计算时间
(69条消息) python:计算程序运行时间_Caesar6666的博客-CSDN博客_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语言笔记_遂古之初,谁传道之的博客-CSDN博客_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,"秒")