第一个基于 Radix Tree 进行路由查找的 Python web 框架发布了!

2020-07-25 15:21:28 +08:00
 abersheeran

https://github.com/abersheeran/index.py

经过我和 encode 组织(也就是 starlette / django rest framework 的创造者)的交流,他们并不想把基数树查找纳入 starlette 。

本来如果他们愿意纳入,那么 fastapi 也可以获得基数树路由的加持,性能可以获得再次上升。

现在没办法了,我自己整。之前 index.py 使用的是文件树映射路由,虽然很高效,但是很受限。现在我把基数树纳入路由系统,把 index.py 的路由能力提升一大截,任何风格的路由均可以在里面找到。

无论是喜欢 flask/bottle 这种装饰器路由,还是 Django 这种列表式均可以被 index.py 支持。并且无论再复杂的路由都是在代码加载时展开,不会增加服务的任何运行时开销!

什么叫快,这就是快! 官方文档里我不好写,但是既然是论坛,我就这么说了,index.py 目前应该是所有 Python web 框架里最快的,没有之一。fastapi 快在使用了 ASGI + uvicorn,而 index.py 不仅有这两,而且路由系统更高效。

由于我公司有不少项目已经使用了 index.py ,所以请大家放心。后续应该不会有再像这种的破坏性更改了,并且在我和朋友一起创建的公司倒闭之前,我们都会对这个项目进行维护。

如果不幸,我创业失败,我个人也会接着维护这个框架。这也是我在大学里创造的第一个我很满意的项目,也是最后一个(今年毕业了)。说着说着有点伤感……希望我创业有成,不求深圳一套房,能赚几百万我就心满意足。

欢迎大家来拍砖 https://index-py.abersheeran.com/route/

3472 次点击
所在节点    Python
45 条回复
abersheeran
2020-10-06 00:33:24 +08:00
@wdhwg001 ASGI3 里面 __call__ 直接做完所有工作了,完全可以共享到一个 session 对象。

```python
async def __call__(self, scope, receive, send):
session = {}
scope["session"] = session
...

send(...session...)
```
wdhwg001
2020-10-06 19:25:13 +08:00
@abersheeran 但是你的中间件需要调用内层的 Application,而 send 则是一层一层传递下去,直到最后一层 Application 才调用这个 callable 的,所以你不应该在中间件里直接执行这个 send,而是要把它传递到更深层的 ASGI Application 里:

```python
async def __call__(self, scope, receive, send):
session = {}
scope["session"] = session

await self.app(scope, receive, send)
```

这样一来,你就只能存一个 scope 的闭包:

```python
async def __call__(self, scope, receive, send):
session = {}
scope["session"] = session

async def send_wrapper(message):
# do something to store session
scope["session"]["saved"] = True # 这里的闭包是不可靠的
await send(message) # 但是这里是可靠的

await self.app(scope, receive, send_wrapper)
```

但是就像 ASGI 标准里描述的那样,Scope 是会被下一层 Application 复制的,这就使得内层如果真的复制了 Scope 的话,外层对 Scope 的闭包引用读取到的只会是脏数据。我仔细思考过了,觉得这里如果 ASGI 不做调整,ASGI 的实现也不保存 Application 栈的话(因为像 Django 的 Daphne 一样保存栈是很消耗资源的),这里应该是没有解决方案的。

可如果 ASGI 提供一个单例的上下文的话:


```python
async def __call__(self, scope, receive, send):
session = {}
scope["session"] = session # 把它存到一个请求期间的上下文变量,不一定是 Scope

async def send_wrapper(message, scope): # 这里接收一个请求期间的上下文变量,不一定是 Scope
# do something to store session
scope["session"]["saved"] = True # 这里就不是闭包而是普通地用参数了,所以是可靠的
await send(message) # 这里本来就是可靠的

await self.app(scope, receive, send_wrapper)
```

或者,如果修改 ASGI 的规定,使得 Scope 由一个 immutable 变为一个 mutable single instance 的话,任何一个地方都可以取到一个可靠的 Scope 的引用,也就不会存在复制的问题了。
abersheeran
2020-10-07 14:15:32 +08:00
@wdhwg001 你为啥要从 scope["session"] 读数据,直接用 session 变量不就行了?
wdhwg001
2020-10-07 21:04:29 +08:00
@abersheeran 但是也同样无法解决闭包不可靠的问题啊,你只能规定禁止 scope 深拷贝,并且规定禁止 scope["session"] = {}这样的操作。
abersheeran
2020-10-08 17:25:56 +08:00
@wdhwg001 这就只能靠约定了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/693028

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX