V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  kuanat  ›  全部回复第 8 页 / 共 12 页
回复总数  226
1  2  3  4  5  6  7  8  9  10 ... 12  
309 天前
回复了 bocchi1amos 创建的主题 Python 为什么 Python 会有.venv 虚拟环境的概念?
@cnt2ex #57

这里我说得太简略了。

在设计这个 import 机制的 1.x 版本,要实现 import * 需要去文件系统里遍历有哪些模块。底层文件系统可能会对某个名为 xyz 的模块,返回 XYZ/Xyz/xyz 几个不同的结果。当时对于这个问题的解决方案是设计 __all__ 让维护者自己声明是哪一个。

之后的 PEP 才明确了模块名应该( should )全小写,import 的所有符号都是小写。再之后 __all__ 才成为一种工程上的控制机制。
309 天前
回复了 Goooooos 创建的主题 Java 吐槽下 Google 开源的组件
@Knife42 #8

自我定位是 long time lurker 所以没有什么社交账号。

v2ex 发帖的初衷是想在 AI 生成内容的时代留下一点有价值的东西。
310 天前
回复了 bocchi1amos 创建的主题 Python 为什么 Python 会有.venv 虚拟环境的概念?
@frostming #54

我又看了一遍自己写的东西,其实不太准确,我这重新描述一下。

版本选择之所以是 NP 问题,源于好几个假设。其中有几个假设是没法改变的,能够改变的还有两个:

- 一个包可以声明自己依赖零个或多个特定版本的包。
- 不允许同时选择同一个包的两个不同版本。

第一条过于严格了。如果把特定版本换成一个范围,这个问题就简单多了。第二条也可以适当放宽,和第一条一样,都是建立在 semantic versioning 主动向后兼容的假设之上。虽然不能引入同一个包的 1.X.X 和 1.Y.Y ,但是可以同时引入 1.X.X 和 2.Z.Z 。

这两个条件放宽之后,NP 问题就不存在了。但是对 APT/RPM/Node/Python 这些起步较早的社区来说,这两个要求依然太难了。

至于主包覆盖依赖的限制,这是用来解决菱形依赖的,不是规避 NP 问题的核心措施。还是之前的例子,只要保证 C 符合 semantic versioning 向后兼容就好了。这个措施实际体现的是解决问题的思路转变。

具体的来源比较分散记不清了,我凭印象做个总结。第一个做 NP 规避的应该是 Rust/Cargo 。之后 Go 做了一个叫 Dep 的类 Cargo 实现,实践了一段时间,吸取经验教训,重做之后形成了正式的 Go mod 方案。Rust/Go 用相同的方法解决菱形依赖,但是基础思路是不一样的。这一点从 Rust 总是选择最高版本,而 Go 总是选择最低版本能看出来。

这里想象一个场景:A==1.1.0 依赖 B==1.5.0 ,之后 B 发布 B==1.6.0 ,由于 B 引入了非兼容改变,导致 A==1.1.0 无法依赖 B==1.6.0 构建。这个时间节点,按照 Rust 的设计,所有依赖 A 的用户(包括依赖 A 的老用户)都会受到影响,而 Go 这边只有同时依赖 A==1.1.0 和 B==1.6.0 的新用户(老用户不受影响)才会受影响。

之后 A/B 至少有一方要打补丁发新版。Rust 认为要么 A 在 B 没有提供补丁的情况下,主动发新版声明不兼容 B==1.6.0 ,要么 B 发新版修复对 A 的支持。实际上在开源社区这两个事情都是很难的。Go 的设计是除非用户主动升级,都会保持作者发布时的最低依赖版本,(毕竟发布那个时刻的版本依赖几乎是都可以构建的)这样就给 A/B 争取了非常多的修复时间。

Rust 的设计者更希望为开发者提供最好的体验,希望一己之力解决所有问题。Go 的设计思路是依靠社区合作,依赖所有人主动去帮助解决对自己来说比较容易,而别人不好解决的问题。所以你能看到,Go 官方一直不遗余力地推动向后兼容,因为 Go 的整套实现逻辑都强依赖整个社区对于兼容性规范的共识。



最后赞美 pnpm ,感谢!
310 天前
回复了 hankli 创建的主题 程序员 试一下用 VersionFox 替代 asdf-vm?
@hankli #7

我一开始没注意到 VersionFox 是跨全平台的。为了兼容 Windows/PS 的话,确实单可执行文件比脚本靠谱。(我觉得理智一点的开发者,在 Windows 环境不用 WSL ,也应该用 MSYS2 吧哈哈)
310 天前
回复了 hankli 创建的主题 程序员 试一下用 VersionFox 替代 asdf-vm?
支持一下~

asdf shell 一直都有,global/local/shell 都支持。我记得 shell 的实现比较粗暴,就是类似 ENV=xxx cmd 的方式。

shim 机制的问题在于需要 reshim ,比如 python pip 安装了某个可执行文件,需要 reshim 才能在当前 shell $PATH 索引到。极小概率的情况,比如某些程序运行后释放执行脚本,又硬编码 #!env python 这样会导致出错。

asdf 有个 direnv 插件,可以管理环境变量,解决每次执行都要 shim 查找的问题。(话说慢真是个问题吗?)

asdf 的优点是插件可以比较方便复用已有的构建脚本,本地构建安装而不是下载二进制文件。

另外我个人比较喜欢这种脚本都用 git 做管理的模式。
310 天前
回复了 bocchi1amos 创建的主题 Python 为什么 Python 会有.venv 虚拟环境的概念?
@kuanat #47

再做一点补充。

Python 3 是 2008 年左右发布的。这个时间点上,如果 Python 决定重写 import hook ,将版本号纳入成为包名的一部分,支持安装同一个包的多个版本,就没有今天虚拟环境什么事了。

这个改动和“不做官方包管理”不冲突。不做官方包管理是正确的选择,在那个时间点上,很难做得好,特别是这些实现都要用 C 来写。

但是底层限制所限,同一个解释器环境不能安装同一个包的多个版本,那包管理器是永远无法摆脱虚拟环境的。
310 天前
回复了 bocchi1amos 创建的主题 Python 为什么 Python 会有.venv 虚拟环境的概念?
“为什么要有虚拟环境”这个问题比较好回答,就是为了隔离。我觉得楼主真正想问的是,或者说这个问题有意义的点在于,为什么 Python 没有“现代”一些的包管理机制?

楼上已经有不少人提到了,Python 不支持同时安装一个包的多个版本。要解释“为什么”不支持,那就比较麻烦了。

这要回到 Python 最早设计包这个概念的时候,当初的决定导致了,不可能在不做 breaking change 的情况下,改变这个行为或者说添加版本机制。这个设计决策的时间点在 1.X 版本,估计大部分人都没有用过,好在 PEP 文档还是可以一窥设计思路的。


我这里提个看上去无关的问题,为什么 Python 需要 __all__ 来支持 from XXX import *?

答案是 Python 的 import 机制是基于文件系统的,包名就是路径名。基于文件系统就意味着,包名无法区分 XXX/Xxx/xxx 的,因为文件系统不确定是否是大小写敏感的。

你可能会觉得包名就是路径名,那给包名后面加上版本号不就行了吗?理论上是的,很多现代一点的语言的包管理就是这么做的。那 Python 为什么做不到?主要原因是 Python 流行起来之后,不可能在不影响生态的情况下做这样的改动了。理论上 Python 2/3 的时候有这个机会,但是 Python 没有做这个变动,这与 import 的实现机制有关。

Python 的 import hook 包括标准库,都涉及到自举( bootstrap ),所以是用 C 写的。更重要的是,增加版本号意味着 Python 要官方实现包管理机制,而包管理是个理论和实践都非常难的事情。Python 选择继续采取社区的“虚拟环境”方案,我个人认为这是个正确的选择。


这个问题到这里其实就差不多说清楚了,不过我打算再补充一些内容。

包管理问题的难点在于版本选择,目的是要找到某个包的完整的(所有)、兼容的(不能包含相冲突的,比如同一个包的两个版本)依赖。这个问题有多难?我印象大概 2017 年才有证明,这是一个 NP 完全问题。NP 完全的意思就是,不知道是否存在一个可以稳定在多项式时间内,完成这个解析过程的算法。

所以几乎所有的传统包管理软件只能做个二选一,要么选择正确但是有可能很慢,要么选择时间可控但是可能出错。实际上几乎所有的包管理都选择正确但是慢,或者说正确但是不清楚要花多长时间。前面的证明给了包管理器新的设计思路,要增加限制条件或者说妥协,不去追求完美解决 NP 问题,只做工程上“好用”的解决方案。

具体理论不展开了,我这里简单说一下“现代”包管理的两个基础假设。一是高版本总是向后兼容低版本,不兼容的情况使用 semantic versioning 的 MAJOR 区分。二是主包可以改写间接依赖的版本。第二条不好理解,举个例子:A 是开发者要构建的包,这里叫主包,它直接依赖 B 和 C==1.2.0 ,其中 B 又依赖 C==1.1.0 。这时候要构建 A ,那么 A 对于 C 的要求就会覆盖 B 对于 C 的要求,又因为 C 的 MAJOR 版本没有变,理论上 C==1.2.0 是同时满足 A/B 需求的。当然单独构建 B 的时候,B 作为主包,依旧会使用 C==1.1.0 的版本。这一条放宽了之后,NP 问题的限制就不存在了,这个问题就有了多项式级别的解法。

我接触过的包管理,似乎只有 Rust(cargo)/Go 是基于新理论(即主动规避 NP 问题)的。区别是 Rust 总是选最高版本,而 Go 选最低版本。Go 的实现比 Rust 简介很多很多。其他的包管理都还在跟 NP 问题作斗争。
311 天前
回复了 Goooooos 创建的主题 Java 吐槽下 Google 开源的组件
很多时候不兼容的改动都是“无意识”的,开发者以为修改是向后兼容的,但实际上不是。这种错误我犯过不知道多少次了……


关于向后兼容这个话题,我推荐两个讲座,都有视频和讲义:

- How to design a Linux kernel interface, https://archive.fosdem.org/2016/schedule/event/design_linux_kernel_api/

- Detecting incompatible changes, https://sourcegraph.com/blog/go/gophercon-2019-detecting-incompatible-api-changes

简单做个总结。Linux kernel-userspace API 早期的失误造成的影响已经持续了几十年,很多还将继续影响下去。这些失误的来源多数是设计者想象不到下游开发者会以什么样的方式去使用这些 API 。

规避的措施就是自动化测试,而自动化测试需要对 specification 进行规范化。实际上推动了开发流程的改变,即先公开规范和 API 设计,提供实例代码,接受反馈并修改设计方案,最后再实现功能和测试。而不是过去的先做实现,然后公开 API 接口的模式。

(这个事情做到极致大概类似于 amazon ,先开发布会,然后再开发)

第二个讲座虽然是 Golang 的,但指导意义很大。核心是如何从技术上自动判定某个改动是否会影响兼容性,进而对如何编写“面向未来可兼容扩展”的 API 接口提供理论支持。Golang 的开发团队为 Go1 的兼容性做了很大的努力,有非常多的案例经验可以参考借鉴。
312 天前
回复了 rivercherdeeeeee 创建的主题 骑行 自行车选择合理推荐
我推荐个迪卡侬 Gravel 120 ,官方价 3999 的样子。迪卡侬自有品牌性价比比较高。

这个型号一般叫瓜车,通过性介于山地和公路之间,城市间骑行偶尔有烂路什么的问题不大,比公路好多了。

车架几何比较舒适,只有单盘,齿比只能说 40 速度够用。再就是这个价位因为套件什么的都比较省成本,装配看脸,多让师傅调一调。
我提供一点额外的视角,有关面试的。这个活动前两天上了 Hacker News 的头条,长期看 HN 的话会注意到类似的活动还有其他语言的版本。

很早之前我司有个内存远小于数据集的版本的同类面试题,后来我主张给砍掉了。原因有两个方面,一是区分度不高,用在校招上,绝大部分人难以回答应用相关的优化,都集中在算法上;用在社招上,脱离了主要应用场景,和八股文没什么差别。另一个方面是开放式问题对面试官要求太高,对于不在预设方向的答案难以量化打分。



回到这个题目本身。

纸面上的问题有纸面上的解法,现实里的问题有现实的应对策略。可能直觉上这是个算法题,但实际上作为比赛,那就是算法、经验、工程、原理和细节多个方面的事情了。

- 经验

社招的技术面试更看重经验,但是经验这个东西很难准确量化,甚至连标准化量化的手段都很少。

我个人对于经验的定义是“分析、定位问题的能力”,这个能力是在技术之外各行各业通用的。一般来说,能准确地用技术语言描述问题,用客观可验证的手段确认问题的核心所在,那问题就已经解决了大半。

所以我在面试里更喜欢问一些类似 profiling/debug 工具、流程的细节,因为我觉得愿意用工具、数据辅助分析,水平是要高出凭印象去解决问题的,当然这是我的一家之言。

这个投递第一天上 HN 的时候,最高的讨论是有关 IO 瓶颈的,然而这个方向是错误的。即便是 HN 这个水平相对较高的社区,低水平的讨论也是大量存在的。当然现在再去看经过社区筛选的高赞结果,就比较有指导意义了。

- 工程

考虑测试环境是 Linux 而且 RAM 32GB > DATASET 12GB ,整个测试跑五次,去掉最高最低结果。除非这个程序特别离谱,占用了超过 20GB 的内存,那么绝大多数情况下,这个文件已经在 page cache 里面了。所以跑一次是 IO 问题,跑很多次就不是 IO 问题了。

一个非常 naive 的单线程实现大概是 240s 左右,不考虑其他因素的话,8 核心测试机上可以预期到 30s 的水平,观察一下榜单,基本上 60s 以内的方案都用到了并行处理。

把工程因素放到最前面说是因为它以最低的成本实现了最大程度的优化。但是这个事情作为面试题是不合适的,因为掌握多线程是最基础的,面试的目的并不是为了区分会不会多线程。

- 原理

这个场景确实存在 IO 瓶颈,但它发生在 kernel/userspace 之间,而非 RAM 与外置存储之间。用户态 read() 需要 syscall 将 kernel 管理的 page cache 里的内容复制到用户空间。这个行为越多,效率就越低。而 MMAP 机制绕开了这个 context 切换,所以提供了真正的 IO 层面的优化。

如果再观察一下榜单里的实现,基本上 30s 上下的方案里,都用了 MappedByteBuffer/FileChannel 之类的调用。换句话说,理解 MMAP 可以在多线程的基础上,稳定将结果优化到多线程的理论上限。

但这个筛选条件略微苛刻了,要么需要比较好的科班基础,要么就要恰好做过类似的业务。最终在进入技术面的数量有限的人群里,能准确回答的寥寥无几,导致缺乏区分度,反正大家都不会。(不是水平问题,而是几率问题)

再往下就是字符串处理了,我相信如果跑个火焰图看一下,30s 上下的方案性能热点应该在自定义的 parser 上。

因为这个竞赛是 Java 的,开发者更习惯的是用 Java 提供的高级抽象,相关的实现都是内存/线程安全的,但是会因为各种检查变慢。

这里不好说到底能优化多少,但是 25s 以内的实现方案里的 parser 基本都是扫描特定字符,而不是用标准库字符串方法了。10s 左右的方案几乎都考虑到了内存分配、变量重用等等技巧。但是这样非常具体的案例在面试里是没有可考察性的,除非应聘者自己主动提出了这个方案。

- 算法

终于轮到算法出场了。对于这样一个场景,算法唯一的要求就是 one pass ,意思是边读取边计算已经读取过的结果里的最大、最小和平均,而不是完全缓存之后再统一计算。

如果是求中位数的话,我觉得倒是可以拿出来讨论。我不清楚是不是有完全准确的 one pass 中位数算法。回到现实里,对于这么大的数据集,求解目标要不要完全精准有可能在数量级上影响实现效率。所以真正考察算法的时候,我会偏好问 bloom 过滤器之类的方向。

这其实也是整个问题里我相对认可的一个点,与其空泛的问 MapReduce/Streaming 之类的,完全不如考察在解决其他问题时,展现出来的触类旁通的能力。只是这个问题又太简单了,而且性能提升很小,甚至性能提升的主要来源是避免了内存分配和 GC 。

多数时候我们都希望开发者有算法基础,但是实际应用里却不希望开发者手撸算法。面试过程里考察对于算法的理解更多体现在应用层面,知道并理解常见算法的复杂度上下界,以此可以来指导方案选择。

但现实的问题是,要么大家都会要么大家都不会,就比如这个场景里,所有人都会选择 hash 结构用来存储结果,所以没有区分度。

- 细节

进入到 10s 水平,再往后的优化几乎就是抠实现细节了。

这个层面的优化,和问题场景强相关,意思就是这些手段是难以复用的。对于 C/C++ 背景的开发者比较好理解,算法逻辑是算法逻辑,数据检查/判断分支是另外的事情。所以剩下的操作无非就是:用 unsafe mmap 替代安全的映射调用,用简化的 hash 方法替代标准实现等等。

还有一个方向是向运行环境做匹配,考虑指令集、cache line 等等微观特征。考虑这里的瓶颈不在 cpu ,我怀疑 SIMD 的方案的有效性。到了这一步,看结果的话又提升了 30%,但实际生产环境可能没人会这么奔放吧。作为面试题来说,能聊到这一步应该 100% 过关了。

这里再补充个插曲,之前有别的面试官面过一个 OI 出身的应聘者,提了一个基于状态机的方案,然后当场把面试官说懵了。后来几个人回看面试记录,证明他说的方案是没问题的。这就是我说的开放性问题对于面试官的要求太高了。

行业里的开发者,一般非科班出身很少会接触状态机。主要原因是业务上需要状态机相关算法的场景非常优先,以状态机作为优化手段的可移植性又太差,除非特别核心的逻辑不得不用,很少会主动选择。



反正现在的就业环境就这样,面试造火箭。我写这些东西就是提供个思路,其实把视角拉远一点,这个具体的题目没有多少值得讨论的东西,解决问题的逻辑更加重要。
322 天前
回复了 Cooky 创建的主题 Linux Arch 大危机, Gentoo 开始提供二进制包
Gentoo 提供二进制预编译内核大概一年多了吧,这个比较重要。相对来说软件包二进制版本没那么必要,毕竟把 Gentoo 当 GUI 主力的用户,基本都有自己的编译机。

我用 Gentoo 的时间也有十几年了,但我的主力桌面系统是 Fedora ,Gentoo 更多是个 meta 系统,用来完成特定任务和功能的。

放到十年前,我会把 Gentoo 当作服务器的主力系统跑,现在更多是用它来作为基础构建系统,来打包特定的软件,做成容器镜像使用。

另一个用途也还是当作构建机器使用,用来配置交叉工具链,编译一些嵌入式设备或者不同架构上的应用。主要是考虑到它基于源代码的特性,一方面比较好排查依赖相关的问题,另一方面 use flag 比较好做版本和特性 pinning 。

还有一个重要特性是 prefix ,用来在 mac 或者主力 linux 上,管理那些需要自行编译、不在官方源当中的软件。
单纯映射上下左右有很多方法,一般要么是 asdw 要么是 hjkl ,这个改键可以从系统层面全局做。如果只是在编辑区用,多数都是类 vim 的插件方式。

但是 IDE 层面,没有哪一家真考虑过对纯键盘做支持。IDEA 不行,VS 也不行。即便它们都有类似切换显示界面的功能(比如开启、关闭文件列表区、内置终端),但是都没有输入焦点的设计,展示了对应的界面,输入焦点不一定能切换过去。

再就是缺少统一的快捷键逻辑,比如现在的输入焦点在内置终端里面,那很多 ctrl 的快捷键组合就会和 IDE 本身冲突了。
反向端口映射

adb reverser tcp:80 tcp:8080

第一个 80 是模拟器里面的,浏览器访问 localhost 80 会转向 host 8080 。
325 天前
回复了 shuiguomayi 创建的主题 Linux 这是对 Linux 正确的使用方法么?
分区话题比较复杂,一般性的建议是用发行版默认的文件系统和分区表。

另外 ESP 比较特殊,取决于 firmware 支持,大部分要求是 FAT32 ,在苹果电脑上要苹果的那个格式。挂载点现在推荐 /efi 或者 /boot ,特别是多系统引导环境,绝大多数情况下 /boot/efi 一样用。

发行版的 Point/Rolling Release 现在的分界线不是特别明显了,往严格里面说 Debian 这种算 Point Release ,而 Arch 这种算 Rolling ,像 Ubuntu/Fedora 介于二者之间。可能看 LTS 支持会更靠谱一些。我个人的分类是看官方维护的内核是只 backport 补丁,还是会追 mainline 版本。Rolling Release 也可以假装当 Point Release 来用,只要把官方内核版本锁了就行。

如果你希望系统层面上支持回滚,可以考虑 Fedora Silverblue 这类基于 ostree 的,或者 NixOS 这种声明式的,核心思想都是 Immutable system partition ,升级过程类似安卓设备上常见的 A/B partitions 。
326 天前
回复了 Befehishaber 创建的主题 Linux 请教下不同系统间的硬中断响应时间
这个事情优先看 jitter 容忍阈值,其次才是 latency 。如果几百毫秒延迟可以接受的话,我估计 RT-Preempt 内核是可以做到的。RH 系还有 Ubuntu 都有相应的发行版,只是都是收费的。

音频相关对实时性要求比较高,一般现场回放延迟容忍大概在 20ms 以内,如果是舞台耳返的话,大概是 5~10 毫秒左右。目前还是很难用 linux RT 做实时效果合成的。

我印象 x86 RT 大概 99% 的话可以做到 30ms 上下,这个要看具体硬件情况。
如果没有硬件级别的漏洞,一般来说 TEE Attestation 是无法伪造的。

但是能用 TEE 的场景很少,因为你要在设备出厂的之前就把私钥写入 TEE 里面,所以基本上只有手机厂商和微信(支付)这种会用。使用的方式主要是用 TEE 内置密钥在 TEE 内进行加密解密,或者在 TEE 内用内置密钥对一段信息进行签名。

你说的这个场景,属于 TEE 签名应用的一种,这个结果是无法伪造的。

在无法伪造 TEE 结果的情况下,要伪造 BL 设备信息等等,用的方法是降级。某些早期设备并不具备 TEE 硬件,所以能够通过 hook 这个校验请求,欺骗系统对于硬件型号的识别,使其认为该设备不具备 TEE 能力,于是降级到非硬件的检测方式上,从而绕过相关的检测。
@kuanat #1

这个方法不一定全适用,看堡垒机是什么样的,能 ssh 的话才可以。
327 天前
回复了 sampeng 创建的主题 程序员 一个疑问,现在是人均一台开发机了?
我翻了一下楼主的提问记录,没有别的意思,只是想判断你是不是有能力自己回答这个问题。

我觉得你想问的只需要几看一遍官方简介就够了,这个文档甚至不满一页。使用场景、延迟这些关键点都回答到了,完全不需要思考。

https://code.visualstudio.com/docs/remote/remote-overview
应用自己不体面,操作系统想让它体面可太难了。

我用折叠屏两个月了,这个功能说实话除了保持前台有点意义,其他应用场景都是产品经理想象出来的,聊胜于无。
1  2  3  4  5  6  7  8  9  10 ... 12  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2952 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 27ms · UTC 12:34 · PVG 20:34 · LAX 04:34 · JFK 07:34
Developed with CodeLauncher
♥ Do have faith in what you're doing.