V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  lxdlam  ›  全部回复第 4 页 / 共 5 页
回复总数  98
1  2  3  4  5  
2021-12-17 15:11:06 +08:00
回复了 kingofzihua 创建的主题 Linux 问一个协程方面的问题
@lxdlam 基于终端 -> 基于中断
2021-12-17 15:08:25 +08:00
回复了 kingofzihua 创建的主题 Linux 问一个协程方面的问题
@ipwx 其实“非常准确明白这些并发方法”本身是一种提升了异步编程门槛的行为,这一串概念能引出来七八个名词和一大堆文章。我个人是非常乐意看见 goroutine 出现的,虽然确实是 dirty and hack 的,但是它足够简单,确确实实解决了实际问题(虽然我还是认为~~go 是垃圾~~)。

对于语言来说,提供一个尽可能统一的抽象,并让不同的 runtime 去实现不同的做法,再实现不同的生态,是一个非常好的做法,也是 Rust 社区正在采纳的做法。这确实会导致出现“事实标准”这一情况(比如 tokio 现在的绝对领导地位),但是给了用户在 consistent 的 interface 下,可以自主根据 workload 切换运行方式的自由。

实际上,阻塞和不阻塞不是异步问题的本源,归根到底还是我们希望每个任务都能够拿到足够多的时间片去跑,而不是要么被无用的 task 频繁占用 CPU ,要么在等一些其实没有意义事情而导致时间流失。从这两个角度出发,一方面我们尝试通过各种方式来更巧妙地让 task 在正确的时候和地方执行,而另一方面我们也在尽力去把各种有这种所谓“无用等待”的地方做成 pubsub 的事件行为把等待让出来,给其他 task 时间。说来也比较奇妙,CPU 和操作系统设计的时候已经采纳了基于终端的事件通知机制,但是应用层全面用到这个特性还是过去了很久。

至于 Worse is better 还是 Do the right thing ,我们都可以另起一次讨论了 :)。
2021-12-17 14:10:55 +08:00
回复了 kingofzihua 创建的主题 Linux 问一个协程方面的问题
@ipwx stackful 和 stackless 最大的区别不是保存调用栈的问题,是可不可以在任意函数中启动异步调用的问题,这个问题最经典的例子就是 js 所谓的有色函数,或者说 async/await 的传染问题。考虑一个非常经典的例子:

```
async function g() { return 123; }

function f(n) {
let x = (await g()) + n;
return x;
}
```

假定这个函数是可以运行的,那就有一个问题:`g` 要被调度走,肯定有其他函数要切入运行,栈要被更改,那当 `g` 执行完的时候,`x` 和 `n` 咋办?我们有两种思路:
1. 调用 `g` 的时候,我们记一下调用栈,这下 `f`, `x` 和 `n` 我都记下来了;
2. 让 `f` 也变成 `g` 一样的东西,这样 `f` 自己就会记录 `x` 和 `n` 的关系。

正好就是有栈和无栈协程的区别。

Project Loom 也打算把 stack 存下来放在 Java Heap 里面,搞成 stackful 的。至于 Fibers 为啥挂了,是因为 Fibers 把一个指挥内核调度的可能性给了用户,误用的可能性更高,比如可能跟系统的带锁操作形成死锁( fiber 在等一个 syscall 之后 yield ,但是系统在等 fiber 释放执行这个 syscall 的资源),也是一种优先级反转的特例。种种情况下,Fibers 虽然 API 没有被干掉,但是用户不咋用了。
2021-12-17 13:29:39 +08:00
回复了 kingofzihua 创建的主题 Linux 问一个协程方面的问题
@statumer 这是显然的强加因果。

网络编程的崛起之于协程已经是很早的事情了,实际上,nginx 和 Redis 都是单线程 IO 模型( Nginx 1.17 和 Redis 6 才支持的多线程网络 IO 模型),性能并不比后面很多所谓用了多线程 or 协程的应用差,那么协程在这里的作用是什么?从另一个角度,OpenResty 往 Nginx 里面嵌入了一个 LuaJIT ,底层 IO 逻辑完全没变的情况下,为什么比 Nginx 性能好那么多?这些和协程崛起相关没有任何直接联系。

关于二三点,既然你已经提到了 go ,为什么不去看看 go 的源码实现和 Scheduler 设计? Design Doc ( https://docs.google.com/document/d/1TTj4T2JO42uD5ID9e89oa0sLKhJYD0Y_kqxDv3I3XMw/edit#heading=h.c3s328639mw9 )和 1.17 的源码 ( https://cs.opensource.google/go/go/+/refs/tags/go1.17.5:src/runtime/proc.go;bpv=1;bpt=0 )都说明了 Go 的工作方式正是我所说的在多核系统下,会用另一个线程去跑 blocking syscall ,对于你的程序来说,这部分 syscall 就是 non-blocking 的。同样在 Java 最新的协程方案 Project Loom 里面,工作方式也是一样的 ( https://blogs.oracle.com/javamagazine/post/going-inside-javas-project-loom-and-virtual-threads )。特别要提示一点,虽然现在 Go 确实在可以 poll 读文件的情况下使用 epoll ,但是在 bsd 环境下 Go 现在还是使用 blocking syscall ,而更早的 Go 版本(我没记错是 1.12 以及之前)同样使用的 blocking 的文件 syscall 去读文件。

实际上,如果你真的对所谓的“只是对有无调用栈的取舍”做出了理解的话,你就不会陷入这种强加因果的关系。对于传统的线程,我们会有两种程度的开销:一个是线程自身占用 memory 的开销,这个和系统的默认栈大小有关,这导致了我们的内存占用会随着线程申请数量,这个线程自身的申请也需要通过 syscall ,时间和内存资源占用都存在 overhead ;另一个角度,虽然根据机器和系统不同数据有差异,但是普遍来说,native thread 切换的开销并不小,对于 常用 Linux 发行版来说,这个切换通常不少于 1ms 。当我们实现了用户侧调度,我们可以通过巧妙地 GC 管理等减少这种异步结构的申请和释放开销,通过剔除和当前应用无关的系统 OS 数据字段同步达到更快的上下文切换,甚至直接基于状态机模型舍弃这部分开销,得到普遍更好的执行时间。更进一步来说,OS Level 的调度是 generic 的,内核针对的是任何任务的调度,而对于我们的应用,我们和 runtime 更容易知道我们的调度侧重点和优势,能够把时间和优先级排布做的更精妙,自然能够带来一定的性能提升,这才是用户侧调度的意义所在,也是协程这类结构的性能提升所在。

我同意异步的 IO 会比起同步 IO 有性能提升,虽然平台不同变量较大,但在普遍比较下 IOCP 确实性能和系统利用率是强于 epoll 的,io_uring 确实是未来的方向。但是这部分的性能提升和线程以及协程本身开销优化没有任何关系,假如我们认为线程和协程切换都是零开销的话,那使用哪种结构都影响不了在同一种 IO 下的调度开销。顺带补充一点,线程的上下文切换和调度也是要 involve syscall 的,用户侧实现调度的话能够减少这些 syscall 的次数。

最后,异步是一个很复杂的概念,但是我们可以抛弃一些严谨性的情况下认为异步就是并发。对于并发来说,根据你观察的 level 不同,多进程对于操作系统来说是并发的,多线程对于应用是并发的,而我多次提到,所谓的协程就是一种用户调度抽象,实际上和多线程相比就是执行模型的差距,本质上和多线程没有区别。

最后,如果你认为在当时文章里描述的 LWP 和 Linux Thread 的调度没有任何区别的话,那可能不求甚解的是你。Java 1.3 是 2002 年发布的,而 Linux 真正实现了内核可抢占是在 2003 年的 2.6 版本。由于 1:N 的设计,当某个 task 开始调用 blocking syscall 的时候,其他的所有 task 都没有机会被唤醒,更别提调度到其他 core 去执行;而对于 Solaris 的调度,LWP 可以任意被调度到可用的 kernal thread 上,进而有机会被调度到其他 CPU core 上( https://www.usenix.org/legacy/publications/library/proceedings/sa92/eykholt.pdf )。这些历史背景才是当时选择的原因。当然,Linux 现在对实时性的支持已经非常好了,所以 Project Loom 重拾历史积淀,再次把用户侧线程引入 Java 。
2021-12-16 16:54:47 +08:00
回复了 publicly 创建的主题 2021 你呢?今年最大的改变是什么?
1. 买了很多以前买不起但是很喜欢的东西;
2. 玩了更多优秀的游戏,看了不少 GDC 演讲,了解了很多以前不知道的技术细节;
3. 又开始写文章了。
2021-12-16 16:24:21 +08:00
回复了 kingofzihua 创建的主题 Linux 问一个协程方面的问题
@statumer 协程能不能火起来跟 epoll 没有任何直接联系。

epoll 的出现是因为需要解决 IO 过程中信号等待的问题,能把时间交出来去干一些其他事情,这也就是我说的这个“在内核态实现的调度反而还有点类似协程的味道”。而 syscall 或者 IO 阻塞和协程本身没有任何联系,这都是因为协程是一个用户侧调度的 continuation ,系统层面只能感知到 thread ,如果多个协程按照 1:N 模型跑在同一个线程里面,任意一个有阻塞的 syscall 一定会 block 住,和你是否使用协程无关,反过来说,在使用 epoll 的情况下,把 fd 注册完后扔到一个线程里面去等待,跟你是否使用协程也没有本质的性能区别(如果无视线程切换开销的话)。换句话说,如果我们是一个多核系统,完全可以引入第二个线程在不同的核来做轮询同步 IO ,并在成功后向第一个线程发送消息,对于第一个线程来说,这个过程也是 non-blocking 的,和使用线程或者协程同样没有关系。epoll 就相当于这个“第二个线程”,只是由 Kernel 在机制上做了优化,保证了在单核上也能执行这种高效操作。

如果你要谈为什么 Java 1.1 引入 Green Thread 但是 Java 1.3 之后废弃了 Green Thread ,Oracle 的官方文档解释了这个问题 https://web.archive.org/web/20040211225937/http://java.sun.com/developer/technicalArticles/Programming/linux/,最重要的问题在于 1.1 引入 Green Thread 是配合了 Solaris 的 LWP 的实现,而这个 1:N model 在 Linux 下是做不到真实的并行的,而不是所谓的 syscall 阻塞问题。

协程快不快的问题核心是 focus 在用户调度和内核调度带来的各种切换问题,在不同的执行模型、结构模型下天差地别,而不是简单的异步操作的问题。
2021-12-14 12:06:04 +08:00
回复了 kingofzihua 创建的主题 Linux 问一个协程方面的问题
@ipwx Erlang 的 Process 也是很经典的 Actor 实现,在爱立信已经跑了 20 年了
2021-12-14 11:59:09 +08:00
回复了 kingofzihua 创建的主题 Linux 问一个协程方面的问题
“协程”是一个大而空的筐,啥鸡蛋都往里装。Go 的 Goroutine 是 stackful 且在 Go 1.14 之后是基于 signal 的抢占式调度的,Kotlin 是 stackless 但是协作调度的,但是这俩都有人叫做协程。

实际上的“协程”,是一种用户调度抽象。有基本 OS 概念的人都知道,进程( Process )是负责资源隔离的,而真正的运行调度单元是线程( OS Thread )。线程不是免费的,这导致我们如果创建一大堆线程,必定涉及了资源的扩张,而实际上的很多 task 虽然对实时性、执行效率有要求,却不需要这么多资源(比如 IO 任务),我们该如何让这些任务能够更好地执行,而不每次都开一个线程呢?这就是协程的本来目的。

通俗来说,一个语言有没有协程,并不意味着这个语言没有这种抽象调度能力。Lisp 系的 call/cc 和 C 的 setjmp/longjmp 也可以实现某种程度上的协程,甚至更简单的,只要一个语言有能够将一个运行过程封装到一个内存结构上的能力(例如,C++ 有 operator() 的 struct ),基于这个能力写一个 scheduler ,你也发明了一个协程。

协程为何性能高?这也是一个网络迷思:如果你的 task 如上面描述的,是一个低资源占用但是高实时消耗的,那当然是显而易见的性能提升(线程内核态调度延迟一般是比协程用户态调度更慢的),但是这不是银弹,如果你的 task 需要独占资源,那么你的线程调度同样能做到跟协程一样快。

那么,我们该如何认识协程?实际上来说,这是一个异步计算结构的问题:
1. 抢占式调度( preemptive ) vs 协作式调度( cooperative )
2. 有栈结构( stackful ) vs 无栈结构( stackless )
3. 跟系统 Thread 的 mapping 关系:1:1, N:1 和 N:M
等等。这些关键词网络上都有非常优秀的资料,就轮不到我在这里扯淡了。认识协程最关键的部分,实际上还是看语言提供的能力(语言结构、标准库等),以及语言的目标领域。

楼主举得 NIO 的例子实际上跟这个话题相去甚远:NIO 用的是 kernel 提供的 IO Multiplexing 或者 Async IO 能力( epoll/kqueue/io_uring/IOCP ),这个在内核态实现的调度反而还有点类似协程的味道。
2021-11-19 18:48:05 +08:00
回复了 Mohanson 创建的主题 分享发现 当得知有一笔亿计数的美元遗产...
育碧?
2021-10-19 16:06:37 +08:00
回复了 shilianmlxg 创建的主题 Apple mbp 有必要买个 ac+吗
AC+ 就是个保险,一般来说预算足够可以直接上,因为 mac 维修成本确实高,这个沉没成本其实看个人接受程度
2021-10-19 11:48:58 +08:00
回复了 Voyty 创建的主题 MacBook Pro Macbook Pro 大家准备下单什么配置呢?最好附上你的使用场景
16,Max 24 核 GPU,32G RAM,2T SSD,写代码+全功能工作站
2021-09-29 11:48:18 +08:00
回复了 InDom 创建的主题 Linux 迫于可能无法黑苹果,求推荐你在用的 Linux 发行版与桌面。
大学时用过一段时间 Elementary OS, 后面的主力是 Manjaro 。现在是 mac 了。
2021-06-16 11:01:09 +08:00
回复了 luozhiyun 创建的主题 分享发现 国行 Xbox Series X 体验
@qq316107934 老哥莫非是 shs ?
2021-06-06 16:32:50 +08:00
回复了 noahhhh 创建的主题 Android Xperia 1III 到手了,大家有什么想问的吗
同国行首发,一般来说早上起床 wifi 开一个视频会议+蓝牙连耳机去公司,一个小时 15% 左右的电消耗,基本可以接受,在公司也是随时无线充电板上一放就行,系统小缺陷反正用过索尼的懂的都懂。
两个比较大的问题点是:
1. 充电的时候 888 很容易发热,然后过一会儿就可能会过热强降 60Hz,打游戏可以开 H.S.,对我这种习惯睡觉前充电看视频的有点影响;
2. 全面屏手势没有优化过,AOSP 有的 Bug 就原封不动搬过来,具体可以看 https://support.google.com/pixelphone/thread/71923225/android-11-issue-with-gesture-navigation-and-full-screen-apps?hl=en,横屏全屏游戏 or 视频会有一点问题。
就我个人来说,游戏都在三大主机平台上不玩手游,单纯听歌+IM+日常使用完全是足够的,续航和发热也基本能接受,索尼移动去年盈利不是没道理的。
2021-05-07 16:22:06 +08:00
回复了 djyde 创建的主题 分享发现 意外发现 Xbox Series S 外接硬盘也能直接运行游戏
@djyde 商店里可以筛选 `Optimized for Xbox X|S`
2020-04-23 21:28:28 +08:00
回复了 hnbcinfo 创建的主题 问与答 我的 GitHub 挂了,怎么回事
按 Github Status 的说法的确是发生了什么问题,https://www.githubstatus.com/incidents/2y6v4ltq26g7
感觉你可以去问问T4U的开发者,他们就是做到了ios上的一个透明代理后的twitter客户端
1  2  3  4  5  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5672 人在线   最高记录 6543   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 44ms · UTC 03:13 · PVG 11:13 · LAX 20:13 · JFK 23:13
Developed with CodeLauncher
♥ Do have faith in what you're doing.