首页 > 其他分享 >Taichi语言学习笔记-1

Taichi语言学习笔记-1

时间:2024-03-16 17:01:04浏览次数:21  
标签:__ kernel Taichi taichi python 笔记 ti scope 语言

Taichi语言学习笔记-1

这个语言我在上大学的时候就听说过,以高性能著称,当时一个99行代码渲染冰雪奇缘的视频在b站上斩获了不小的播放量,那个时候我就想来尝试一下这个非常厉害的语言。不过到了今天,我才有充分的“理由”“不得不”学习这个语言,遂写下这篇文章,一方面促进自己学习,另一方面也请广大网友有理有据拷打我,让我借大伙之力进步更快。

这一篇博客主要想写Taichi与python之间的关系与区别,针对Taichi本身的各种内容之后会慢慢学习。

What?

这门语言,或者说这个DSL,实际上是嵌入python中的:至少在一部分使用场景下,他的语法和python几乎没什么差别,甚至写都是写在一个文件下的:

import taichi as ti  
ti.init(arch=ti.cpu)  
  
@ti.func  
def inv_square(x): # A Taichi function  
	return 1.0 / (x * x)  
  
@ti.kernel  
def partial_sum(n: int) -> float: # A kernel  
	total = 0.0  
	for i in range(1, n + 1):  
		total += inv_square(n)  
	return total  
  
partial_sum(1000)

这是官方给的案例。可以看到这里taichi被作为一个包引进进来,做了一个简单的初始化,就开始进行了计算。一切看起来都是那么友好,而且和python看起来可以说是完全一样。

Why?

官方在文档中给出的说法是:将taichi内嵌入python,并使用其作为自己的前端,是有原因的:易学易用,不需要繁琐的编译什么的环节,可以借助极为丰富的python生态来加速开发,且python的AST非常适合拿来分析以供下一步运算,这些都使得python成为了当仁不让地首选。

问题当然是有的:那就是python还是慢的,纯python脚本开发出来的taichi应用初始化的时候会有点费劲,需要一些时间。

那到底这玩意是怎么让代码变快的呢?

HOW?

简单来说这玩意实际上跑了一个独立于python runtime的另外一个runtime,taichi在这之中下足了功夫:只要标注了ti.kernel代码块,就会被用一种奇妙的方式塞到taichi runtime里,在那里代码得到了非常良好的优化,这使得最终代码运行效率提升。

所以叫成taichi lang的确是有道理的:taichi runtime对于喂进去的python代码是有比较多要求的,至少比python要求的多,所以涉及到taichi的那一部分就必须用一套新的(虽然其实几乎一样)的规则来去写代码。

那么自然而然地,代码就必须分成两块:taichi scope和python scope。用上述代码做例子的话:

#########python scope#############
import taichi as ti  
ti.init(arch=ti.cpu)  
#########python scope END#########

###########taichi scope###########
@ti.func  
def inv_square(x): # A Taichi function  
	return 1.0 / (x * x)  
###########taichi scope END#######

###########taichi scope###########
@ti.kernel  
def partial_sum(n: int) -> float: # A kernel  
	total = 0.0  
	for i in range(1, n + 1):  
		total += inv_square(n)  
	return total  
###########taichi scope END#######

#########python scope#############
partial_sum(1000)
#########python scope END#########

关于taichi的代码被划分成一部分,剩下的都是python scope。

既然是两个scope,其中的概念被分成两个也是合情合理的。taichi scope中的function实际上和python中的function是分开的。

有时候我更喜欢这样理解这一整套系统:python作为一个胶水语言,他要做的事情就是安排好taichi scope内的代码按照什么顺序、以什么样子运行,以及其他的脏活(读数据)累活(处理数据,输出output),taichi代码就好好做好运算就好。

taichi kernel就是python代码需要管理的运算单元。一个kernel定义了一个运算任务。kernel可以在python scope代码中的任何部分出现,但唯独不能出现在另一个taichi kernel或taichi func里。

@ti.kernel
def hello():
	print("hello.") #可以写原生python代码的,就像这样一样

@ti.kernel
def what():
	hello() # -> pylint不会报错,但运行会报错

if __name__ == "__main__":
	hello() # -> correct

上述代码自然是有问题的。不过至少目前这个版本来说,其报错信息依旧不太友好:

[Taichi] version 1.7.0, llvm 15.0.4, commit 2fd24490, linux, python 3.11.2
[Taichi] Starting on arch=x64
Traceback (most recent call last):
  File "/home/leviathan/everything/project/taichi-test/test.py", line 13, in <module>
    @ti.kernek
     ^^^^^^^^^
  File "/home/leviathan/.local/lib/python3.11/site-packages/taichi/__init__.py", line 23, in __getattr__
    raise AttributeError(f"module '{__name__}' has no attribute '{attr}'")
AttributeError: module 'taichi' has no attribute 'kernek'. Did you mean: 'kernel'?

那么很好理解,ti.func就是针对kernel的function。python scope自然是不可以调用这些func,其需要放在kernel或者其他taichi function里被调用。

不过有个坏消息:ti.func是不允许运行时递归的,因为ti实际上是这样处理函数调用的:直接内联,即将所有func最后合成出一个超级大的func,如果做出运行时递归的话很有可能会导致出现无限长的展开导致出问题。

值得注意的一点是,只要你不调用,写错的代码是不会报错的。

接下来是几个错误例子:

@ti.func
def error():
  error()
# 运行后会告诉你栈溢出。

count = 0
@ti.func
def out_count():
  if count <= 2:
    count += 1
    out_count()
# 实际上count是编译时常量,所以也会爆炸

@ti.func
def error_yield():
  count = 0
  if count == 2:
    count += 1
    yield count
    error_yield()
# taichi貌似还没支持yield,写出来运行后会告诉你yield不被支持。

类型

方法声明

taichi实际上还是比较在意类型的。假设如下代码:

@ti.kernel
def test(a):
  print(a)

if __name__ == "__main__":
  test(12)
@ti.kernel
def test(a: int):
  return a

if __name__ == "__main__":
  test(12)

上述两段代码是无法运行的。Taichi对于kernel的声明并不像Python那样那么的随便,其args内所有的参数都要明确的给出类型,且如果存在返回值,那么也要说明返回类型。

对于@ti.func就没那么多规矩了。

数据类型

Taichi和Python有很多细微上不一样的地方。对于类型而言,Taichi是一个静态类型语言,且一个变量的类型实际上在Taichi的编译期间就已经确定好了。官网例子举得就相当不错:

@ti.kernel  
def test():  
	x = 1 # x is the integer 1  
	x = 3.14 # x is an integer, so the value 3.14 is cast to 3 and x takes the value 3  
	x = ti.Vector([1, 1]) # Error!

这实际上就是静态类型的特点。第一次出现实际上就相当于完成了声明与初始化,之后就是基于这一类型来做事,所以会有上述的执行情况。

至此,基本上就讲述清楚两者之间的关系与区别了。

标签:__,kernel,Taichi,taichi,python,笔记,ti,scope,语言
From: https://www.cnblogs.com/leviathanwww/p/18077285

相关文章

  • C语言葵花宝典之——文件操作
    前言:在之前的学习中,我们所写的C语言程序总是在运行结束之后,就会自动销毁,那如果我们想将一个结果进行长期存储应该如何操作呢?这时候就需要我们用文件来操作。目录1、什么是文件?1.1程序文件1.2数据文件1.3文件名2、二进制文件和文本文件2.1文本文件:2.2二进制文......
  • 网络编程笔记目录
    网络编程笔记基础概念socket编程https://www.cnblogs.com/AndreaDO/p/18072371三次握手和四次挥手高并发服务器(多进程与多线程)https://www.cnblogs.com/AndreaDO/p/18073716selecthttps://www.cnblogs.com/AndreaDO/p/18074786poll和epollhttps://www.cnblogs.com/And......
  • C语言基础-1、指针
    一、取地址运算运算符&scanf("%d",&i);中的&是获得变量的地址,它的操作对象必须是变量&不能对没有地址的东西取地址:&(a+b),&(a++)二、指针就是保存地址的变量inti;int*p=&i;int*p,q//p是一个指针,是一个指向int型的指针变量,q则是一个单纯的int型变量1、指针变量变量......
  • 数据结构知识总结笔记------第四章:串(2)串的简单模式匹配算法、KMP算法、KMP算法的改进
    1、简单模式匹配算法对一个串中某子串的定位操作称为串的模式匹配,其中待定位的子串称为模式串。算法的基本思想:从主串的第一个位置起和模式串的第一个字符开始比较,如果相等,则继续逐一比较后续字符;否则从主串的第二个字符开始,再重新用上一步的方法与模式串中的字符做比较,以......
  • C++学习笔记——002
    在一个类里建立一个const时,不能给他初值:classfoo{public:foo():i(100){}private:constinti=100;//错误!!!};//可以通过这样的方式来进行初始化foo::foo():i(100){} classTest{public:Test():a(0){}enum{size1=100,size2=200};......
  • C++学习笔记——001
    C++是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言,支持过程化编程、面向对象编程和泛型编程。C++是C的一个超集,事实上,任何合法的C程序都是合法的C++程序。注意:使用静态类型的编程语言是在编译时执行类型检查,而不是在运行时执行类型检查。 <>......
  • C语言-动态内存管理
    动态内存管理为什么存在动态内存分配动态内存函数介绍malloc和freecallocrealloc常见动态内存错误1对NULL指针的解引用操作2对动态开辟空间的越界访问3对非动态开辟内存使用free释放4使用free释放一块动态开辟内存的一部分5.对同一块动态内存多次释放6.动态开辟......
  • P3374 【模板】树状数组 动态求连续区间和 刷题笔记
    我们创建如下的树状数组来辅助操作该数组每个s[i]处于第几层取决于其二进制最后低位的1处于从右往左数第几列显然所有奇数的最右边一位都是1即其最低位的1处于右边第一列所以所有的奇数处于第一层而2,6,10,14的最低位1处于右边第二列 所以这些数处于第二层 8的最......
  • 日期问题 刷题笔记
    思路枚举19600101到20591231这个区间的数获得年月日 判断是否合法如果合法 关于题目给出的日期有三种可能年/月/日日/月/年月/日/年判断是否和题目给出的日期符合如果符合输出闰年{1.被4整除不被100整除  2.被400整除}补位写法“%02d" 如果不足两位......
  • 2024-03-16:用go语言,给你一个正整数数组 nums, 每一次操作中,你可以从 nums 中选择 任意
    2024-03-16:用go语言,给你一个正整数数组nums,每一次操作中,你可以从nums中选择任意一个数并将它减小到恰好一半。(注意,在后续操作中你可以对减半过的数继续执行操作)请你返回将nums数组和至少减少一半的最少操作数。输入:nums=[5,19,8,1]。输出:3。答案2024-03-16:......