您的当前位置:首页正文

你不要乱写sleep(6)——简评华为昇腾演示代码翻车

2024-11-10 来源:个人技术集锦

庄晓立/LIIGO,20240520。

官方回应

先看一段新闻报道(来源https://kxstock.hexun.com/2024-05-16/212868824.html):

演示代码分析

q = input(">> ")  // 读取用户输入的指令
ret = rag.query(q, ...)  // 将用户指令输入给RAG服务并获取结果
ret.write("...")  // 将RAG服务返回的图片数据存储到本地磁盘

主要流程:创建RAG服务对象rag(代码位于main函数上方,此图未体现),读取用户指令,请求服务,存储服务返回数据。input是Python系统函数,query和write均为RAG服务接口API。

失误过程分析

由于Ctrl+C强制终止程序运行触发了Python程序内置的TRACEBACK功能,即输出函数调用栈。下文进一步分析调用栈将会解读出更多信息。

调用栈分析

调用栈显示,main.py调用了ret.write(),ret.write()调用了time.sleep(6)。

也就是说,time.sleep(6)代码是写在ret.write()函数内部的。这一点我感觉很反常。

正常来说,流程应该是这样的:query, sleep, write。不知道处于何种考虑,演示者似乎不想让我们看到sleep,故意把sleep隐藏到write内部。事实上如果演示过程一切正常,我们根本不知道有sleep(6)的存在;只不过因为一个意外回车才导致sleep暴露在我们眼前。

说一下为什么我感觉不正常。

这里涉及两个角色,一个是模块的实现者(生产者),一个是模块的使用者(消费者)。也就是说一个提供API、一个调用API,双方各行其责。

rag.query()是API,使用者负责调用API,实现者负责实现API内部代码,也就是说query()函数里面的代码是实现者写的。

ret是query()的返回值,因而ret.write()也是API,write()函数里面的代码是实现者写的。

可是sleep()应该是调用者的工作呀,应该写在API函数外面,不应该写在API函数里面。

而且看ret.write()的命名,其功能很简单很明确,就是写出文件,按常理不应该有sleep功能。

以上讨论的是API未提供等待机制的情况。按说成熟的API设计应该提供等待机制,可行方案是:或1,把rag.query()设计为异步函数(调用方异步等待),或2,新增ret.waitForComplete()类似接口(在ret.write()之前调用)。

考虑到他们演示的模块还不是正式版,还没有发布,API不成熟没有等待机制也可以理解。

让使用者等待调用完成是很尴尬的,因为使用者不能预知要等多久。作为演示代码也无所谓,根据经验就暂定等6秒吧,可以的。

但是使用者等待的时机,应该是在query之后write之前呀。write函数里面,那不是你的领地;把sleep(6)写在write里面,是很反常的。因为你API尚未完善需要调用方等待呀,DEMO代码应该明确体现出sleep调用呀。

写在最后

此演示主要面向开发者,我认为其目的大抵有二:1、展示模块功能,体现自身技术实力,2、展示调用接口,体现API友好易用。

前述两个演示目的都未达成,毫无疑问是“翻车”了。原本想展示技术实力,结果让人怀疑演示造假。原本想展示API友好易用,结果竟然需要sleep(6)等待。

虽然华为昇腾社区官方及时出面,否认了演示造假,但是该回应缺乏细节和逻辑,可信度不够。

我建议华为昇腾社区还要尽快多做一些工作,才能及时消除大面积负面影响:

  • 尽快将当前版本模块原样发布体验板,让网友在线试用,证实该功能可用
  • 尽快解释API设计逻辑,为何没有异步等待机制
  • 尽快解释为何将原本属于调用方的sleep(6)写在模块实现代码内部
显示全文