Open thautwarm opened 2 years ago
为了用方便debug的语言做全平台开发(包括iOS和Android),实现了TraffyIR.UnityPython。
亮点是用了koka的思路,根据continuation是否存在来编译解释器的asm。做了benchmark,结果 (optimize=true的debug模式) 是非生成器代码比cpython略快(差距10%以内),非生成器比cpython慢一个数量级以内 (从1 yield 到 100_0000 比 cpython慢3倍)。
解释器的IR存在很大性能提升空间,目前每一次执行ir都会动态判断是否存在continuation。
如果不使用"inline threading"而使用字节码解释器,生成器代码会更快一点,但非生成器代码更慢,且不支持.NET native exception,且python try-catch-finally的字节码编译太烧脑,遂使用"inline threading"方案。
目前这点性能开销不是问题。一个有强力IDE支持、可热更新、动态执行、无伤兼容全平台的Python实现,意义重大。
目前TraffyIR.UnityPython 的限制:
不支持Python的一部分“罕见”元方法。例如,对比较操作只支持__eq__和__lt__(TODO: 支持le? 用户保证 le与eq和lt的相容?),且__lt__和__eq__必须返回bool
__eq__
__lt__
不支持type以外的其他的metaclass。但是支持__init_subclass__,足以应付大部分元编程场景。
type
__init_subclass__
不支持NotImplemented, 包括__ror__这些元方法
NotImplemented
__ror__
不支持用StopIteration做迭代终止。for循环的实现不依赖exception, raise StopIteration不会引起for loop正常退出,而是跑错误。
StopIteration
for
raise StopIteration
不支持raise a from cause。这主要是为了兼容.NET的native exception
raise a from cause
bool不是整数的子类型,True + 1报错。这一点python挺折磨人,而不实现bool <: int不仅减小工作量,也让我自己的使用体验更佳。
bool
True + 1
int不是任意大整数而是int64,float是float32。这是为了提升性能,顺便和unity交换数据时避免复杂cast。
int
int64
float
float32
list.reverse不是O(1)的。list内部实现是.NET的List,因此reverse是O(n)操作 (TODO: 未来支持双向list实现?)
list.reverse
支持Python丰富的传参模式和参数验证,除了3.8引入的positional only arguments (XXX: TraffyIR.UnityPython基于Python 3.10,但不是所有feature都支持)
yield/await/yield from不能出现在try-catch语句里,也不能出现在finally语句块里,但可以出现在try-finally语句块里。这是因为try语句实现使用了.NET的try-catch机制,与.NET有同样的限制。
yield/await/yield from
await Task.Yield()做运行时的特殊处理,行为上等同于yield但不开启async generator。
await Task.Yield()
yield
async不耦合asyncio,实现正确的coroutine和thread分离机制。用户可以控制event loop,默认event loop被一个Unity根对象的coroutine执行。
为了用方便debug的语言做全平台开发(包括iOS和Android),实现了TraffyIR.UnityPython。
亮点是用了koka的思路,根据continuation是否存在来编译解释器的asm。做了benchmark,结果 (optimize=true的debug模式) 是非生成器代码比cpython略快(差距10%以内),非生成器比cpython慢一个数量级以内 (从1 yield 到 100_0000 比 cpython慢3倍)。
解释器的IR存在很大性能提升空间,目前每一次执行ir都会动态判断是否存在continuation。
如果不使用"inline threading"而使用字节码解释器,生成器代码会更快一点,但非生成器代码更慢,且不支持.NET native exception,且python try-catch-finally的字节码编译太烧脑,遂使用"inline threading"方案。
目前这点性能开销不是问题。一个有强力IDE支持、可热更新、动态执行、无伤兼容全平台的Python实现,意义重大。
目前TraffyIR.UnityPython 的限制:
不支持Python的一部分“罕见”元方法。例如,对比较操作只支持
__eq__
和__lt__
(TODO: 支持le? 用户保证 le与eq和lt的相容?),且__lt__
和__eq__
必须返回bool不支持
type
以外的其他的metaclass。但是支持__init_subclass__
,足以应付大部分元编程场景。不支持
NotImplemented
, 包括__ror__
这些元方法不支持用
StopIteration
做迭代终止。for
循环的实现不依赖exception,raise StopIteration
不会引起for loop正常退出,而是跑错误。不支持
raise a from cause
。这主要是为了兼容.NET的native exceptionbool
不是整数的子类型,True + 1
报错。这一点python挺折磨人,而不实现bool <: int不仅减小工作量,也让我自己的使用体验更佳。int
不是任意大整数而是int64
,float
是float32
。这是为了提升性能,顺便和unity交换数据时避免复杂cast。list.reverse
不是O(1)的。list内部实现是.NET的List,因此reverse是O(n)操作 (TODO: 未来支持双向list实现?)支持Python丰富的传参模式和参数验证,除了3.8引入的positional only arguments (XXX: TraffyIR.UnityPython基于Python 3.10,但不是所有feature都支持)
yield/await/yield from
不能出现在try-catch语句里,也不能出现在finally语句块里,但可以出现在try-finally语句块里。这是因为try语句实现使用了.NET的try-catch机制,与.NET有同样的限制。await Task.Yield()
做运行时的特殊处理,行为上等同于yield
但不开启async generator。async不耦合asyncio,实现正确的coroutine和thread分离机制。用户可以控制event loop,默认event loop被一个Unity根对象的coroutine执行。