如何做一款面向企业客户的商用级 SDK

从一个小故事开始讲起

在几年前我们刚开始做 ToB 的 SDK 的时候,曾经对接过一家做社交 App 的公司,对方的技术负责人很年轻也很务实。在商务大哥给力的努力下,客户成功完成了产品的接入,并进入线上灰度阶段。

然而,在开始灰度的那天晚上,线上用户出现了很多消息延迟大的投诉,用户的一条消息需要很长时间才能发出去。客户虽然对我们很失望,但依然很努力地在配合我们排查和修复问题。

在两天的时间里,我们给客户改进了多个版本,每次给版本的时候我们都说“已经找到问题了,这个版本肯定可以”,但每次效果都不理想。两天之后,客户的技术负责人很严肃地询问了我们一个问题:“从这两天的排障过程和修复过程来看,我想确认一下你们这是一款商用级的产品吗?”

在那个晚上,我们开始冷静地思考一个问题:一款优秀的商用级 SDK 应该怎么做?

一年的努力功亏一篑

*近教育行业被政策打压地非常厉害,但在两年前,这是个 PaaS 服务的兵家必争之地。我们有一家做在线英语教学的客户,一直在对接我们的 TRTC。这个客户对质量要求非常苛刻,他们很早便引入了赛马机制,将多家 PaaS 服务商拉入到自己的供应商集群,互为灾备,并进行质量评估,看谁的质量好就用谁的产品。

在*开始对接的时候,我们的产品质量还不是很优秀,几个关键指标跟竞品都有差距。这倒不是问题,优化总要有一个过程,于是我们一个迭代一个迭代地去跟进。因为客户的版本发布速度非常慢,所以我们需要在两个版本之间都做好问题分析和优化落地,稳抓稳打地慢慢降低工单率。就这样,经过了将近一年的时间,产品各项指标都已经很不错了,我们非常有信心在下一个版本超过友商获得质量上的*地位。

但就在我们信心满满地等待客户上线的灰度反馈时,客户突然抛出一个问题:“你们的 SDK 有一个对音频模块的自动重启逻辑,这个逻辑会在切换线路时影响到其他供应商的音频模块, 这是*对不能容忍的”。因为引入多家供应商赛马的意义就在于保证可以有灾备,如果一家供应商影响了其他供应商的稳定性,这个灾备便没有了意义,因此客户对我们异常失望,放量计划无限期搁置。

面对一年的努力功亏一篑,我们开始接受一个现实:每位同事都可能会因为手滑引入缺陷,但对团队而言代价却是难以承受的,怎么办?

回到正题,接下来我会介绍一下过去的这些日子里,我们怎么去应对这个问题。不过在此之前,我需要先介绍一下我们的产品:

我们是做什么的?

我们团队所开发的是一套面向企业级客户的 SDK,包括用于实时音视频通讯的 TRTC SDK;用于消息通信的 IM SDK;用于直播推流和播放的 LIVE SDK ;以及用于短视频录制和编辑的 UGC SDK

%title插图%num

产品面向的客户群很多:有做泛互联网行业的,比如在社交领域长期霸榜苹果应用商店的某知名 App;也有在线教育领域的很多知名机构,教学模式包括 1V1、小班课、大班课等等;也有金融和保险领域的巨无霸,他们会使用我们的产品将现有的业务尽快地跟互联网融合;还有各行各业的中小型企业,他们虽然可能并不出名,但确实支撑我们国家互联网经济持续繁荣的基石;对了,还有做毕业设计的学生,虽然他们不会付费,但保不齐人家会在毕业后给自己的老板推荐我们的产品呢。

面对这么多行业领域的客户,有喜有忧,喜的是这是一桩很好的生意,忧的是这里有着车载斗量的压力:因为 SDK 这种形态的技术产品,如果要面向企业客户去服务,那真是打从娘胎里一出来就注定了坎坷的一生

首先是客户群体

  • 客户所属行业分布广,教育、泛互、金融,不同的客户对产品的需求差异性大。
  • 客户接入周期长,大客户在接入过程中会不断追加新需求和新特性,与此同时,客户对交付周期要求又很苛刻。

然后是产品形态

  • SDK 对专业性要求是比较高的,别人家的客户都只需要理解 http 的 get 和 post 就行了,俺们家的客户就得知道多线程安全、内存泄漏、前后台切换,苹果隐私合规要求,还有 android 的 gradle 配置方法和 windows 的 stl 兼容问题…
  • 涉及平台众多,iOS、Android、Windows、Mac、Web,每个方向都需要很长时间的积累和沉淀。同时,在微信的强大的影响力面前,我们又增加了一个新的平台——微信小程序。

*后是交付成本

  • SDK 完成接入后,成不成要依赖客户的*终反馈,但往往客户的反馈周期很长,迭代周期也很长。
  • SDK 版本多,平台多,这也就意味着测试工作是海量的。就说一个细节,这么多平台和版本,全量编译都需要两个小时,转测和发版就更不用说了。

面对这个问题,我们的友商做法是:加人

%title插图%num

当然,我们不能这么简单粗暴,毕竟粗放型经济是走不远的,我们还是得从研发体系上用集约的思想去解决问题,这就是接下来要说的重点:从研发、产品、数据和排障等四个方向去认认真真做好一款面向企业服务的 SDK 产品。

%title插图%num

研发体系的优化

在研发体系方面,我们依然遵循腾讯倡导的需求评审=>技术评审=>开发=>测试的流程。但每个环节,我们都结合自身的特点进行了改进。

%title插图%num

1. 怎么做需求评审?

首先是需求评审,我们团队经过这几年的打拼,总结出来*关键的一个点,就是看需求一定要看客户背后的意图。有时候客户会跟你说:“我想要你给我增加一个设置视频分辨率和码率的接口”。这个时候你要不要加呢?如果我们只是看客户的需求,那是要加的。但如果我们再问问,“您为什么需要我们加这个接口呢?” 那客户可能就会跟你说:“我觉得你们的画质不行,不够清楚,我要自己调,我要调清楚一点。” 这个时候我们就明白了,我们的需求不是“去增加一个可以设置视频分辨率和码率的接口”,而是去“提升我们的画质以满足客户的需求”。

这两者是不对等的,因为前者客户可能认为只要分辨率调到 4K 就是清晰的,但客户可能误以为“清晰度”就等同于“分辨率”,所以往往会指定一个 4K 的分辨率,却配置了一个 40Kbps 的视频码率。懂音视频的朋友都知道,这样的画面是模糊地没法看得。所以我们在简单版的 API 接口中,都不开分辨率设置接口,而仅仅是提供一个画质等级的接口,以避免客户的错误配置。但我们在得知客户的意图之后,会去了解客户为什么觉得我们画质不行,是跟哪款产品比有差距。进而分析是提升颜色矩阵转换的精度,还是在前处理的*后增加一道锐化,还是视频分辨率不匹配显示分辨率导致的问题,还是 OpenGL 的线性变换和就近变化的差异问题。

2. 怎么做技术评审?

这个部分,我们一般会鼓励大家提供两个以上的方案,然后进入“左右互搏”的模式。因为很多可爱的同事本身也是可爱的急性子,只要能早点写代码,什么都是不重要的。毕竟咱们做研发的成就感,不就来自于把功能做出来看到自己的成果吗。

但我们也不断地告诫自己,我们究竟是做“一票子买卖”还是是“百年老店的生意”。如果是前者,那大可以想到哪里代码就写到哪里;但如果是后者,则需要我们综合考虑多个方案,选择更能可持续发展的方案。

要知道在 ToB 这个领域,我们一不注意就会把自己陷入到做定制需求的套路里。面对业务压力,一开始这样是很解渴的,但随后的维护成本就让自己彻底吃不消了,每天除了救火什么都干不了的团队,也就失去了创造新价值的能力。

3. 怎么做代码合入?

在代码合入方面,我们团队在很早的时候就引入了一套非常严格的代码评审流程,即三级评审:

  • CR 一级:模块的维护者来 review,这一级的目的是让模块的稳定性能够得到保障。毕竟在别人家的田间地头种自己的庄稼,你总不能背着这块地的主人搞小动作不是。
  • CR 二级:自己的 leader 来 review,这是我们整个 CR 的核心基石。很幸运团队有像 taopu 一样负责和认真的 leader,会非常细致的 review 大家的每一行代码,并积*提出意见和建议,在 CR 中提升大家的技术水平。
  • CR 三级:总监负责 review 和 代码合入,这一步更多是抽检,看看哪些同事是真正地爱这款产品,哪些同事则是不那么负责的架构破坏者。

%title插图%num

4. 怎么做功能测试?

*近半年在测试团队,尤其是 svein 和俊哥的大力支持下,我们的自动化测试进步*大。不管是 native sdk 还是 webrtc sdk,自动化测试都能覆盖掉很多刁钻和难以手工覆盖的部分。比如一次通话过程中几十次的“进进出出”,或者是频繁的切换某个状态,这些都是以往手工测试很容易把人逼疯的部分。益于测试团队的持续投入,目前我们的自动化测试系统已经小有成绩。要知道,构建一个面向音视频功能的自动化测试体系,那难度可是非常高的。仔细想想就知道这里面有多少破事儿要解决:

  • 怎么确认画面出来了?
  • 怎么确认声音是正常的?
  • 怎么构造复杂的测试流程和测试序列?
  • 怎么保证测试环境的稳定和不被干扰?
  • 还有*艰苦的:怎么找到足够多又耐操的手机,尤其是水果牌的。

通过需求评审、技术评审、代码审查和自动化测试的多重保护,我们*近已经很久没有再发生前面说的第二个故事里的事情了。即使有些同事一时手滑引入了一些问题,也大都能在 SDK 交付前得到暴露,只是目前我们并不能将这个概率降低到 0% 而已。

%title插图%num

产品体系的优化

作为一款自身不带界面的 SDK,要做到产品体系的优化,就只能去优化技术本身,但这是枯燥且不好度量的。俗话说得好,“文无*,武无第二”,说的就是评判标准的问题。这就好比你画一幅画,如果没有老师指点你怎么才算好,那就会很难度量自己这段时间是水平提高了还是退步了。不然人家丢勒一个德国人,干嘛两次跑到意大利的威尼斯去学画画;又不然怎么会出现很多画家都是在那啥之后才有人开始欣赏他们的作品的呢?

所以说,作为一款面向 ToB 客户的 SDK 产品,要提升产品质量,就得有一些手段和方法,我们是这么做的:

%title插图%num

方法一:通过场景落地来验证产品质量

我们做 TRTC SDK,我们的客户拿 TRTC SDK 的能力去做合唱,去做 K歌,去做语音聊天室,去做视频直播。那我们就只是做好自己的一亩三分地吗?

当然不行,所以我们自己也实打实地开发了一些面向行业场景的 App(也可说是 Demo),比如合唱、语聊、教育、直播等等。并在这些场景的开发过程中,不停地寻找产品的问题和不足,并持续打磨,以确保在产品交付客户之前,在产品体验上就已经达到了一个很好的水平。

比如我们在开发在线合唱的场景时,就经常有人找我问:“rex,我跟你确认一下哈,咱们团队里的同学,究竟都是写代码的程序员,还是想要通过《我是歌手》来改变人生的麦霸?”

%title插图%num

方法二:通过数据体系来评估产品质量

构建一套靠谱的数据体系很重要,这就是把“文无*”的事情变成“武无第二”。通过数据体系,让所有的指标都变成可以比较的数字,并且依托数据分析系统,不断地提升产品质量。

%title插图%num

虽然这个思路大家都很清楚,也都在各自的产品中有所落地,毕竟咱们腾讯的产品团队,谁家还没有一个负责数据运营的同事呢?当然有些比较大的业务,都是有自己的数据运营团队的。

但还是得说,这个事情在 toB 的方向上不好做,难在两点:

  • 不同的客户关注的点是不一样:比如教育客户关注的是稳定性,电商直播关注的是清晰度,秀场直播关注的则是音质。如果我们给一个在线教育客户去过度地优化画质,客户不仅可能不买账,还可能因为我们的优化影响了其他指标而弃用我们的产品。
  • 音视频的表现不是简单地靠 DAU、成功率来衡量的。比如“切课率”这个指标,影响因素非常多,比如网络波动呀,硬件发热呀,麦克风阻抗大呀,显卡驱动不匹配呀,还有可能是用户心情不好砸键盘呀。就说我们有个客户,发现上课的声音效果不好,结果客户很负责,亲自到了学生家去确认,*后发现是 iPad 的保护套把麦克风给遮住了,你说这找谁说理去?

数据体系建设

面对上述挑战,我们还是得从技术角度去解决问题,毕竟靠堆人是不行的,这生意得做出毛利率才能长久地坚持下去。

庆幸的是这方面我们还是做得不错的,尤其是我们团队一向比较在意数据,团队里还有一等一的聪明脑袋负责数据体系的建构。比如我们在自己的引擎内部的各个关键模块都做了数据“挂节点”。这些模块会每时每刻将近百个技术指标以一秒一次的频率反馈给统计模块,在统计模块进行汇总之后,再实时上传到服务器上。

%title插图%num

基于这些海量的数据信息,仅仅靠 group by 和 count 、where 等 SQL 语句做简单的统计分析是肯定没用的,因为这样的分析得不出任何有价值的信息。

比如一次糟糕的通话体验,可能出现过一次 2s 的卡顿,但是这些数值如果仅仅是用来做大盘平均分析,那这次 2s 的卡顿就“淹没”在了海量的通话数据里,你拿到的*终的平均值甚至不会有小数点上的一个波动。

针对这个问题,团队中的 xuanyi 和 yuting 两位同事,基于对以往 badcase 的经验综合分析,构建了一套“根因分析系统”,并用了将近半年的时间,不断地打磨其准确性。到目前为止,这套系统对于 badcase 的分析已经接近人工挨个 case 分析的准确性,为团队节省了不知道多少人力。

%title插图%num

排障体系

回到*初的小故事,客户之所以怀疑我们的产品不是一款商用级的产品,*大的问题就在排障体系上。因为客户也不是*终用户,客户在面对自己用户的反馈和投诉时,往往也是很难拿到*手信息的。如果我们将排障过程演化成了:我们 <=> 客户<=>客户的用户,之间的复杂关系,这个事情就很容易引发矛盾和冲突。

所以我们在接受了早期的失败教训之后,就励精图治建设了一套商业级的排障系统。经过这几年的努力,这套系统已经越来越强大了,也承载了越来越多的能力。目前已经能够做到分析过去两周内任何一个用户的任何一次体验问题,并能够定位到技术层面的缺陷或者环境方面的问题。

%title插图%num

于此同时,在线日志和离线日志系统的双重保障,也让排障的信息变得更加容易获取。以往比较困难的线上死锁问题和调用时序问题,也开始不再那么可怕和束手无措。

%title插图%num

当然,面对这么多的客户,靠一个团队的人力是不可能搞定数千个客户的技术支持和售后服务的,靠两个也不行。不过作为一款腾讯云上的老产品,我们的 TRTC 和 IM 很早就接入了腾讯云的安灯系统。借助安灯的问题跟踪和信息流转能力,中小客户的问题也得到及时的处理和沉淀。

%title插图%num

总结

从 2016 年加入腾讯云,团队到今天已经走过了五年,我们用了五年时间去学习如何做一款商用级的 SDK。虽然现在来说,我们做得还不够好,但至少可以回答几年前客户的质问,我们现在还是有信心并且有能力做好一款商用级的 SDK 产品的,而且不止一个。

平均交付时长减少五天!腾讯TAPD助力企业高效交付!

刚刚,在由中国信息通信院主办的「OSCAR开源产业大会」腾讯TAPD联合中国信息通信院及腾讯研究院,共同发布《2021年企业敏捷协作数据报告》。

在市场环境快速变化的背景下,企业的敏捷协作呈现出怎样的特点?未来敏捷协作又将迎来什么样的发展趋势?让我们先睹为快!

8e3fba71197d9cbb140baeca0fd17dab.png

ca27c22357bfb0838a71ac18081de803.png

64f9a984414b4d7be7fce74e52ba14de.png

3d0720ec3531cf202e8b8aba383f5580.png

dcc6ccd7b3368612d3091adfa7cd840c.png

6760aa80753cc03820947d0dc32ebd69.png

3b598703ee3b68e88fa420344f9803f0.png

如何调用一个 function 而不用等待其返回

比如现在有两个 function,一个 fun a,一个 fun b,在 fun a 中需要调用 fun b,但是对 b 的执行结果毫不关心,也不用等待 b 执行完,怎么实现比较合适?
Fun function 调用 等待11 条回复 • 2021-09-25 02:35:01 +08:00
wd 1
wd 2 天前 via iPhone
async 或者线程
kealm 2
kealm 2 天前
“`js
async function b() {
return new Promise((resolve) => setTimeout(resolve, 10000))
}

function a() {
console.time(‘b’)
b()
console.timeEnd(‘b’)
}

async function aa() {
console.time(‘b’)
await b()
console.timeEnd(‘b’)
}
“`
ila 3
ila 2 天前 via Android
celery
Abbeyok 4
Abbeyok 2 天前 via Android
threading.Thread
rootit 5
rootit 2 天前
python 肯定首选 asyncio.create_task() 了,再次 threading 起线程
zhangdeplives 6
zhangdeplives 2 天前
了解一下异步
demonzoo 7
demonzoo 2 天前
就直接在 a 里面调用 b() 就好了啊。。。不要 await b()
IsaacYoung 8
IsaacYoung 2 天前
thread
meiyoumingzi6 9
meiyoumingzi6 2 天前
哈哈哈哈哈哈 我当时刚接触 python 的时候也思考过这个问题

0. 多线程, 把 b 丢进新的线程计算
1. 多进程, 同上
3. 协程 async
4. celcry 等异步框架
5. 换 golang, 无脑 go 就行了 [手动狗头
yianing 10
yianing 2 天前 via Android
golang:go 就完了
dangyuluo 11
dangyuluo 2 天前
这种情况 Async 比多线程要好

使用 pycharm 遇到问题

1
aloxaf 2 天前 ❤️ 2
稍等,我去拿一下水晶球(
zhangdeplives 2
zhangdeplives 2 天前 ❤️ 1
建议移动主题到悬丝诊脉
z740713651 3
z740713651 2 天前
塔罗牌我放家里了
您要不发个面相
麻衣神相我能对着翻
ila 4
ila 2 天前 via Android
掐指一算,明天放假,后来再告诉你
ReferenceE 5
ReferenceE 2 天前 via Android
嗨呀,这个问题我见过,上次就是上面的老哥巴拉巴拉给我算卦算好的
nightwitch 6
nightwitch 2 天前
我抽了一张塔罗牌,占卜的结果是愚者。
ErwinCheung 7
ErwinCheung 2 天前
嗨呀,这个问题我见过,上次就是上面的老哥巴拉巴拉给我算卦算好的
abersheeran 8
abersheeran 2 天前
你等我翻一下易经看看你是什么问题哈。
MiketsuSmasher 9
MiketsuSmasher 2 天前
我刚刚算过一卦,问题应该出在楼主那里
sweetsorrow211 10
sweetsorrow211 1 天前
你等等,等我二大爷托梦了我问问他
cco 11
cco 1 天前
刚烧了一个乌龟壳,显示的卦象是 䝕齛?䬡??,我找专家确认了一下,翻译过来是:这是楼主的锅。

求一个获取 lambda 对象源代码的方法

我先说一下我试过的方法,以及为什么不行:

inspect.getsource:这玩意只能获取*行,比如定义一个多行的 lambda 它也只能拿到*行。并且如果 lambda 前面还有东西,它会一并拿回来,这部满足我的需求,我只想要从 lambda 关键词开始到整个 lambda 结束的定义,是不是原有格式我不在乎,只要完整且不多余就行。
lambda_object.__code__.co_firstlineno:这个同上,实际上 inspect.getsource 就是用这个值去拿的。这个值只能标识*行所在,却不能标识开始的横轴位置以及*后的坐标。
我能想到的解决方式是直接拿到 lambda 对象的字节码,从字节码反编译到 Python 源代码,但是我需要 2.7 和 3.9 、3.10 三个版本同时兼容的……我对字节码反编译不太熟悉,目前找到的都是以文件为单位的反编译,不知道有没有以对象为代码的反编译库。

我想做一个把类似于 User.filter(lambda user: user.age > 18) 这样的语句翻译到 SQL 的玩意。但是卡在了这里。

lambda 字节码 tso urce18 条回复 • 2021-09-26 11:07:16 +08:00
chinvo 1
chinvo 1 天前 ❤️ 1
python 不清楚, C# 里面的 lambda 会被编译成 expression, 就能直接用了.

python 大概也有类似机制?
v2exblog 2
v2exblog 1 天前
同问
hsfzxjy 3
hsfzxjy 1 天前 via Android
我之前实现一个拿 lambda 的 AST 的功能,但这个有个限制就是需要保证前置的 token 是固定的,具体可参考 https://github.com/hsfzxjy/lambdex/blob/master/lambdex/utils/ast.py#L97

比如要求用户写成 def_(lambda: …) ,然后将这个 lambda 对象以及字符串 ‘def_’ 传入这个函数,就可以拿到 AST

可能对你有帮助
hsfzxjy 4
hsfzxjy 1 天前 via Android
@hsfzxjy #3 这个在 3.5-3.10 应该都可以,2.7.没测过
penguinWWY 5
penguinWWY 1 天前
先说这个问题,瞎猜一下

一个方法是通过这个 lambda 反向拿到 module,然后把这个 py 文件编译到 ast 再做遍历

另一个是 PyCodeObject 对象中有一个属性是 co_linetable,这个属性的类型是一个 PyBytesObject,可以看 cpython 中对它的解析方法,应该可以拿到起始行列和终止行列
https://github.com/python/cpython/blob/main/Include/cpython/code.h#L77
penguinWWY 6
penguinWWY 1 天前
@hsfzxjy
@abersheeran

再借楼说下,https://www.v2ex.com/t/804224#reply4
二位有没有兴趣
chenxytw 7
chenxytw 1 天前 ❤️ 1
你的问题本身我不是很了解….但从你要做的事情来看,我在想,是不是没必要用你题目中提出的方法。而是通过实现 User 里 age 的 `__gt__` 之类的魔术方法,在这之中保存一些状态,然后将 Model 本身传给这个 lambda 就能做到你想要的事情了…这应该是*常见的实现类似事情的做法了….当然因为你要做的事情没有详细描述,所以不知道是不是有什么需求导致了你不采用这种方案….
fgwmlhdkkkw 8
fgwmlhdkkkw 1 天前 via Android
@chenxytw Python 的 orm 都是这么做的。
2i2Re2PLMaDnghL 9
2i2Re2PLMaDnghL 1 天前
参考下 PyMacro ?
abersheeran 10
abersheeran 1 天前
@hsfzxjy 你这个思路我也想到过,但是有一个问题我不知道该如何解决,比如同一行出现两个 lambda……

@penguinWWY 在 CPython 运行时用 Python 拿 PyBytesObject 的原始指针做不到的吧?

@chenxytw 这个办法我也想过,问题在于重载运算符不能把 and 、or 、not 运算给重载了……
penguinWWY 11
penguinWWY 1 天前
@abersheeran 当然是使用 C API 辣
O5oz6z3 12
O5oz6z3 1 天前
本质上也许是寻找一个表达式的源码位置:
1. lambda 有多少行?
2. 同一行里有几个 lambda ?
3. 是否嵌套 lambda ?
4. 是否有’lambda’字面字符串?
http://xion .io/post/code/python-get-lambda-code.html
看到这篇文章和#3 楼的实现,想到一个未验证的思路:对 inspect.getsource() 获取的源码进行修剪并编译成 ast,遍历 ast 提取所有 lambda 节点,用 Python3.9 的 ast.unparse() 获取近似的源码,用 co_code 判断源码编译后是否等价。
hsfzxjy 13
hsfzxjy 1 天前 via Android
@penguinWWY co_linetable 应该只存了行号,co_columntable 能拿到列号,但这是 3.10 新加的,兼容性不太好
hsfzxjy 14
hsfzxjy 1 天前 via Android
@abersheeran 我当时的解决方法是强制用户给同一行的 lambda 加不同的前缀,当然这个就比较丑了。同期待更好的方法
abersheeran 15
abersheeran 1 天前
@O5oz6z3 一语惊醒梦中人,只要对比源码编译后的 __code__ 就行了。一行*多也就几个 lambda 。

@hsfzxjy 好家伙,不同前缀有点暴力了
O5oz6z3 16
O5oz6z3 1 天前
@abersheeran #15 我指的是 __code__.co_code 字节码,是从那篇文章中学来的,虽然我也不确定这个字节码比较是否可靠。顺便写了两个 demo 。
简单的情况:
source_text = inspect.getsourcelines(lambda_func)[0][0]
source_ast = ast.parse(source_text)
lambda_node = next((node for node in ast.walk(source_ast) if isinstance(node, ast.Lambda)), None)
lambda_text = ast.unparse(lambda_node)
复杂的情况:
text = ‘lambda’ + inspect.getsource(lambda_func).partition(‘lambda’)[2].rstrip()
while text:
… try:
… … tree = ast.parse(‘({})’.format(text))
… … srcs = [ast.unparse(node) for node in ast.walk(tree) if isinstance(node, ast.Lambda)]
… … break
… except SyntaxError:
… … text = text[:-1]
test = lambda src: compile(src,”,’eval’).co_consts[0].co_code==lambda_func.__code__.co_code
hits = list(filter(test, srcs))
hsfzxjy 17
hsfzxjy 1 天前 ❤️ 1
@O5oz6z3 #16 co_code 不可靠,一个简单的反例

(lambda: print(1)).__code__.co_code == (lambda: sum(1)).__code__.co_code # True

这是因为变量名一类的不存在于字节码中,而是在 __code__.co_names 里
hsfzxjy 18
hsfzxjy 1 天前 ❤️ 2
还有另一个问题是你要考虑 lambda 所在的闭包,看一个例子

def f():
… a = 1
… return lambda: a + 1
a = 1
f().__code__.co_code == (lambda: a + 1).__code__.co_code # False

这两个 lambda 虽然代码相同但是他们字节码不一样。原因是 f() 中的 a 是个 local 变量,读取时会使用 LOAD_DEREF ;而后一个是 global 变量,读取时会使用 LOAD_GLOBAL 。总而言之 corner cases 有很多很多

能否通过代码直接调起 iOS 系统的截屏功能?

App 想做一个截屏的小功能,主要是截屏的时候,还可以有笔刷稍微绘制一下,具体功能如下:
1. 截屏页面,并可拖动设定截屏区域。
2. 有画笔 /橡皮,可以简单编辑 /绘制截图区域。
3. *后,获取到*终图片的 UIImage 数据。

而这些功能正好是系统的截屏功能(除了第 3 点,系统截屏是直接保存文件)。所以我就想有没有办法直接通过代码的方式,来调起 iOS 系统的截屏功能,用户处理完后能够拿到图片数据。
截屏 功能 绘制 iOS10 条回复 • 2021-09-27 14:24:54 +08:00
wipbssldo 1
wipbssldo 13 天前
对 App 的 view 进行截屏就可以了,没办法也不需要调起 iOS 系统的截屏功能
James369 2
James369 13 天前
@wipbssldo 这样虽然可以,但是我就需要额外的开发 笔刷 /橡皮的功能。
qq2511296 3
qq2511296 13 天前
https://share.api.weibo.cn/share/250411462.html?weibo_id=4332707376341309
感觉想起了多年前看到的 jsbox 作者的一条微博 很像是你要的功能,咋实现的不清楚
minamike 4
minamike 13 天前 ❤️ 1
@James369 笔刷 /橡皮可以直接调用系统的 pencilkit 吧
JHExp 5
JHExp 12 天前
找个第三方的编辑图片的库用下好了
cairnechen 6
cairnechen 12 天前
@qq2511296 链接无法访问
MX123 7
MX123 12 天前
苹果好烦人,有些功能系统已经有了,就是不开放给开发者用,比如扫码功能。
Building 8
Building 12 天前 via iPhone
苹果截屏绘图这套框架是开放的,基本上就是把 View 截图成为 Image 再扔给框架就可以了,什么都不用管。
ryh 9
ryh 3 小时 38 分钟前
@MX123 换一个例子吧,不要张口就来了
https://developer.apple.com/documentation/vision/vnbarcodeobservation
MX123 10
MX123 1 小时 39 分钟前
@ryh 不是 Api,是系统相册这类的功能!

请问 KVM-QEMU 中当虚拟机 insmod 某个 ko 的时候直接死机,如何进行调试?

如题,虚拟机 insmod 某个 ko 的时候直接死机,ko 在物理机的时候是正常使用的 看不到 bug…一点问题都没有,希望有大佬能帮帮我 谢谢大家

insmod 死机 物理机 虚拟9 条回复 • 2021-09-23 10:38:26 +08:00
kakyoin 1
kakyoin 5 天前
看不到 bug,一点修的思路都没有…顶顶~
westoy 2
westoy 5 天前
虚拟机里 dmesg 和 syslog 都没错误提示么?
wzxlovesy 3
wzxlovesy 4 天前 via Android
先看看 KVM 相关的 Log,说不定有有用的信息。如果是 QEMU 闪退,那有可能是什么指令执行错了;如果是 QEMU 宕机没闪退,那尝试用 QEMU 内置的 Monitor Console 看看代码执行到了哪里,卡在哪个内存位置,然后 disassemble 那个位置的代码看看是啥。当然如果能修改 ko 对应的代码的话,print debug 试试。当然还有个猜测是,如果你在宿主机编制了 ko,复制到 QEMU 里运行的话,可能有些编译出来的指令不支持,试试在 QEMU 内部重新编译一下。
lilogo 4
lilogo 4 天前
关于指令不支持这个*近也刚踩过坑,建议可以先看下 VM 内 CPU 指令集。
liuweisj 5
liuweisj 4 天前
给 vm 加个串口,从 console 会有 log 打印出来
feather12315 6
feather12315 4 天前 via Android
启用 kdump
wzxlovesy 7
wzxlovesy 4 天前 via Android
@lilogo 我*近踩过另一个深坑是 code segment 错误,导致发生中断时 QEMU 直接崩溃,当时调了很久的 interrupt handler 死活找不到问题……
kakyoin 8
kakyoin 4 天前
@westoy 应该有,但是 insmod 某个 ko,虚拟机直接卡死,就进不去了,之前用 ssh 可以看到一点,但是后面还是卡住了
kakyoin 9
kakyoin 4 天前
@wzxlovesy 好的!谢谢前辈,我去试试

vscode 怎么设置代理,让测试的 axios 也能够自动使用该代理?

我们使用了一个第三方的库,这个库是用 axios 访问 dropbox 的 API, 比如 https://api.dropboxapi.com/oauth2/token, 但是 dropbox 被墙了,大家都知道。

现在我在操作系统 windows 10 network setting 里面,设置了代理。然后在 vscode 的 config 里面,也设置了 “http.proxy”: “http://xxx.com:8080” 和 “http.proxyStrictSSL”: false

但是,调用该库的时候,还是返回 not authenticated.的。

我用浏览器网页试过了,通过该代理是能够访问 dropbox 的。

谢谢!

p.s. axios 好像是可以直接设置代理的,但我们调用的是第三方的库,这个库里面使用的 axios,我没有办法直接改代码。

axios 代理 VSCode Dropbox12 条回复 • 2021-09-26 13:41:06 +08:00
cz5424 1
cz5424 3 小时 48 分钟前
检查一下代理访问是否需要账号密码
yazoox 2
yazoox 3 小时 40 分钟前
@cz5424 忘记说了,不需要密码。代理是公司内部的结点,用的 squid3 搭的,直接 http://xxx.com:8080 就可以了。浏览器就是用的 switchy omega 这么设置的,正常工作。
renmu123 3
renmu123 3 小时 34 分钟前 via Android
不如魔改一下让三方库支持代理
dcsuibian 4
dcsuibian 3 小时 27 分钟前 ❤️ 1
有点不太明白这个程序是怎么运行的,如果是通过 node 运行的话,不应该让命令行走代理吗?为什么要让 vscode 走代理?
lin07hui 5
lin07hui 3 小时 13 分钟前
vscode 插件开发 or 前端开发 ?
ispengsiqi 6
ispengsiqi 3 小时 6 分钟前
@renmu123 #3 感觉做一个旁路由透明代理可能会还更方便一点
ai277014717 7
ai277014717 2 小时 57 分钟前
使用 terminal 打开 vscode,打开之前设置 http_proxy https_proxy all_porxy 应该可以。
AreYou0k 8
AreYou0k 2 小时 53 分钟前
自己写一个走代理连 dropbox 的 API 的接口, 然后用这个第三方库连自己写的接口. (方案有点捞)
cweijan 9
cweijan 2 小时 40 分钟前
vscode 的代理是设置的内部的服务请求, 没法到影响 axios, 我能想到的方法是用 proxifier 设置系统代理, 这个软件可以匹配指定域名.
EridanusSora 10
EridanusSora 2 小时 23 分钟前
proxifier 代理 node
archean 11
archean 16 分钟前
netsh winhttp set proxy proxy-server=”http://xxx.com:8080″ bypass-list=”*.internaldomain.com”
archean 12
archean 13 分钟前
@archean 没写完发出去了,这个命令可以让很多命令行程序访问 http/https 协议的时候走代理,可以试试能否满足你的要求。

如何在Linux中获取Ram信息?

我们有很多服务器。 有不同类型的供应商和产品。 跟踪他们的硬件是艰苦的工作。 例如,不可能通过打开所有服务器箱来获取ram信息。 Linux魔术来了。 Linux提供了许多命令。 我们可以像下面那样使用dmidecode 。

使用dmidecode获取信息 (Getting Information With dmidecode)

dmidecode is very useful command which can provide information about hardware of the system. dmidecode will list a lot of information about CPU, Memory, Mainboard, Devices, Network etc. by default without providing any option. We will use --type 17 option in order to print detailed Memory or RAM information like below.

dmidecode是非常有用的命令,可以提供有关系统硬件的信息。 默认情况下, dmidecode将列出许多有关CPU,内存,主板,设备,网络等的信息,而无需提供任何选项。 我们将使用--type 17选项来打印详细的内存或RAM信息,如下所示。

$ dmidecode --type 17
Getting Information With dmidecode
Getting Information With dmidecode
使用dmidecode获取信息

We can see that the system has 2048 MB RAM and multiple RAM slots.

我们可以看到系统具有2048 MB RAM和多个RAM插槽。

获取内存大小 (Getting Memory Size)

As we have seen that dmidecode will print a lot of information about the RAM but if we want to strictly filter the RAM size we can use grep command like below by providing Size term.

正如我们已经看到的那样, dmidecode将打印很多有关RAM的信息,但是如果我们要严格过滤RAM大小,可以通过提供Size term来使用grep命令,如下所示。

$ sudo dmidecode --type 17 | grep Size
Getting Memory Size
Getting Memory Size
获取内存大小

获取内存频率(Getting Memory Frequency)

Like RAM size we can also print the frequency of the RAM with grep command. As frequency is expressed with MHz we will provide  Speed to the grep command.

像RAM大小一样,我们也可以使用grep命令打印RAM的频率。 当频率以MHz表示时,我们将为grep命令提供Speed 。

$ sudo dmidecode --type 17 | grep MHz

打印RAM /内存尺寸 (Print RAM/Memory Form Factor)

Memory/RAM has physically different form factors. Currently DIMM or SODIMM is very popular. We can get this information with the following command.

内存/ RAM在物理上有不同的外形尺寸。 当前,DIMM或SODIMM非常流行。 我们可以使用以下命令获取此信息。

$ sudo dmidecode --type 17 | grep Factor
Print RAM/Memory Form Factor
Print RAM/Memory Form Factor
打印RAM /内存尺寸

如何在Linux中获取Ram信息? 信息移植 (How To Get Ram Information In Linux? Infografic)

   How To Get Ram Information In Linux? Infografic
How To Get Ram Information In Linux? Infografic