V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  icexin  ›  全部回复第 1 页 / 共 4 页
回复总数  67
1  2  3  4  
2022-10-17 16:41:34 +08:00
回复了 OrangeAdd 创建的主题 Go 编程语言 关于 Go 垃圾回收栈对象的疑问
基于 tracing 的垃圾回收算法第一步是找到“根”对象,根对象就包括全局对象,栈上对象等。直观的解释是:一个栈上对象可以包含指向堆的成员变量。
一般是通过 jit 编译到机器码的,具体实现上可以有不经过优化的一遍翻译,也可以有多遍的优化编译。可以参考一下 v8 的 https://v8.dev/blog/liftoff
2022-06-22 19:23:19 +08:00
回复了 sbilly 创建的主题 Go 编程语言 有对 gVisor / netstack 比较熟悉的吗?
@gesse 是的
2022-06-13 11:43:45 +08:00
回复了 thewiredguy 创建的主题 Go 编程语言 我怎么觉得 Java 的 JNI 比 Go 的 CGO 要好呢?
跨语言调用 c 模块有其自身的复杂度在,不可能简单,也注定不是平凡的事情,任何语言都要面对。
主要有以下几个问题:
1. 包管理的差异,c 没有官方的包管理,所以库的管理完全看系统,或者团队的约定工具,如 cmake 等。go 其实可以跟 c 一起源码发布成一个 go 的包,见 https://github.com/mattn/go-sqlite3
2. 交叉编译,新的语言基本上都有很方便的交叉编译方案,甚至不需要(脚本语言)。而 c 的交叉编译工具链其实很复杂,搞过嵌入式或者搞过路由器的都知道我在说啥。
3. 数据类型的差异。这部分主要是内存布局的差异带来的。比如一个 c 的 struct 不一定对应着高级语言里面的一个 class 。go 在这一点上其实做的很好了,go 的一个 struct 基本上对应一个 c 的 struct 。指针的概念也跟几乎一致,除了算数运算。所以 cgo 几乎可以不加修改的直接引用 c 的头文件,以及传递 go struct 作为参数给 c 函数。
4. 内存管理的差异。c 是手动管理的内存,所有内存都要自己显式分配和释放。新的语言基本上都有自己的内存管理方案,即 GC 。这就带来了语言之间内存传递的问题,c 分配的内存不会被 go tracing ,go 的内存也不能被 c 手动释放,其他语言类似。
5. 并发模型的差异。这部分基本上是语言自带协程的独特问题。因为 go 里面的协程有自己的栈,而 c 基本上可以认为是操作系统的线程栈。这两者之间的差异会带来诸如 TLS 和栈切换的问题。

所以综合看来,除了第 5 点是 go 特有的,其他语言几乎都有类似的问题。go 引入 cgo 主要是为了解决复用已有的大量 c 库的遗产,不是和 c 无缝调用,混合编程,目前也就 c++做到了和 c 无缝衔接,但为了这个能力 c++也付出了很多代价,到现在还在打补丁。 软件工程没有银弹,作为工程师最主要的工作就是熟悉各个模块的脾性,对症下药,挑选最合适项目的方案,而不是强行套方案,最终不符合预期的时候骂骂咧咧。
2022-06-01 13:54:10 +08:00
回复了 sbilly 创建的主题 Go 编程语言 有对 gVisor / netstack 比较熟悉的吗?
如果想了解使用,可以参考一下我之前写的使用 go 编写的操作系统内核的网络部分,其中使用到了 gvisor 的 netstack 作为协议栈。https://github.com/icexin/eggos
2022-05-05 23:27:36 +08:00
回复了 dzdh 创建的主题 Go 编程语言 苦于没有异常,怎么优雅的捕捉三方包里的 panic
用闭包+工具函数可以达成你的需求 https://gist.github.com/icexin/fd39098dbd8e411d035573d893a46c33
2021-11-30 14:50:41 +08:00
回复了 sunny1688 创建的主题 问与答 关于 golang 碰到的一个问题!
大家回答的点都集中在内存回收上,实际的问题是没有加锁导致的不变式被打破的问题。

实际的 slice 包含 data ,len 和 cap 字段,这些大家也都知道了。slice 结构的不变式是:在任意时刻,data 指向的数据长度都是至少是 len 长度,否则访问 len-1 的数据就会 内存错误。

在题主的代码里面,多个 goroutine 同时对 demo.llist 进行赋值,但因为没有加锁,所以赋值不是原子的,从而会出现一个 goroutine 刚赋值了 data ,还没来得及赋值 data 和 cap 就被其他 goroutine 拿去用了, 破坏了不变式, 从而在扩容的时候就访问了非法内存,从而 panic 。

一段简单代码就可以复现:


package main

import "log"

type T struct {
A, B int
}

func step(t T) T {
if t.B != t.A*2 {
log.Panic(t)
}
x := t.A+1
return T{
A: x,
B: 2*x,
}
}

func main() {
var t = T{
A: 1,
B: 2,
}
for {
go func() {
t = step(t)
}()
}
}
2021-11-30 11:19:12 +08:00
回复了 ryougifujino 创建的主题 NAS 威联通大家存储用的什么模式?
@rwecho 我是用了两个静态盘,一个纯粹备份,按理备份盘寿命会长一些。
2021-11-30 11:07:17 +08:00
回复了 ryougifujino 创建的主题 NAS 威联通大家存储用的什么模式?
家庭用 NAS 数据的安全性更重要,使用静态卷+定时备份,在数据出问题的时候恢复也简单透明。
2021-08-08 14:32:17 +08:00
回复了 icexin 创建的主题 Go 编程语言 将 Go 程序跑在裸机上之 LibOS
@Actrace 感谢关注,目前作为实验性项目,并不具有生产可用性哈。不过业界的确有 unikernel 的研究方向,在嵌入式和云环境还是有一定的使用场景。
2021-08-08 14:29:16 +08:00
回复了 icexin 创建的主题 Go 编程语言 将 Go 程序跑在裸机上之 LibOS
@kwanzaa 感谢关注,这个是我后续尝试的方向,但目前看来比较比较困难,云厂商都会限制上传自定义镜像的格式,特别是目录结构以及对 cloud-init 的支持,比如阿里云的这个 https://www.alibabacloud.com/help/zh/doc-detail/48226.htm?spm=a2c63.p38356.879954.4.3fa81c9287RlTk#concept-d53-2jm-xdb
2021-01-14 15:38:43 +08:00
回复了 jiangwei2222 创建的主题 Go 编程语言 golang 里面为什么要设计 int 这样一个数据类型?
int 跟机器字长一致,这样可以获取最大的执行效率。在不关心数值范围的场景下 int 足够了,比如数组下标。相反如果你在 32 位机器上使用 int64,本来一条指令的事情要变成多条指令。
int32 和 int64 这些一般用于编解码、底层硬件相关,或者是数值范围敏感的场景。
2020-12-09 10:49:37 +08:00
回复了 Peakday 创建的主题 Go 编程语言 go 处理 tcp 长连接丢失数据原因是什么
@labulaka521 在一个 goroutine 里面复用是没问题的,但楼主把数据发送到 channel 里面,在另外一个 goroutine 里面处理,两者会发生不同步,就会产生消费 goroutine 没处理完,新的数据又写入到 buffer 里面了。即使不考虑 buffer 覆盖问题,两个 goroutine 同时访问一块内存也会出现数据竞争。
2020-12-09 10:40:39 +08:00
回复了 Peakday 创建的主题 Go 编程语言 go 处理 tcp 长连接丢失数据原因是什么
你复用了 buffer,新数据过来之后老的 buffer 就被覆盖了。拷贝一份 buffer 发送到 channel 里面。
goroutine 进行阻塞调用比如 sleep 或者 socket 读取并不回阻塞对应的 cpu 核心,go 的 runtime 会把阻塞的 goroutine 切换走置于休眠态,一旦解除阻塞的条件达成,如 sleep 时间到或者 socket 有可读数据,则会唤醒相应的 goroutine,这个过程跟操作系统调度进程很像,所以可以认为 goroutine 就是一个用户态线程实现。回到你的问题,答案是:cpu 有多少个核心跟启动多少个 goroutine 没关系,因为 go 的 runtime 会自动切换走处于阻塞的 goroutine,从而来充分利用 cpu 资源。但是有一个原则是通用的,cpu 密集型的任务尽量启用跟 cpu 核数差不多的 worker,因为在 cpu 密集型任务里面 cpu 一直处于饱和计算状态,无谓的上下文切换反而影响效率。
2020-12-03 23:11:13 +08:00
回复了 vevlins 创建的主题 程序员 协程跟 cpu 有关系吗?
callback 函数不是一个 jmp 指令那么简单,调用者需要传参,保存返回的 PC 指针,有时甚至要保存[caller-saved-registers]( https://stackoverflow.com/questions/9268586/what-are-callee-and-caller-saved-registers);被调用者需要保存调用者的栈帧以方便在函数返回的时候恢复之前的栈帧。这些都是跟具体 CPU 指令相关的,我们没感觉是因为编译器帮按照语言的语义帮抹平了不同 CPU 的差异。
对于 go 这样的每个 goroutine 有自己独立栈的,在切换 goroutine 的时候还需要切换对应的栈寄存器。
2020-12-01 17:55:32 +08:00
回复了 James369 创建的主题 程序员 跨语言之间的调用,原理是什么?
拿 Python 举例吧,用一种易于理解的方式简单说一下。

假设你想让 Python 能调用 c 标准库里面的 puts 来打印字符串,首先需要使用 c 语言编写一个 so 模块,这个模块里面有一个签名类似 PyObject* py_puts(PyObject *self, PyObject *args)这样的 c 函数。
在这个函数内部使用 python 源代码提供的工具函数解析 args,从而获取 python 传递过来的字符串参数,转换成 c 的字符串类型 char*,再传递给 puts 来打印。然后在 python 约定的模块初始化函数里面把 py_puts 注册到 python runtime 里面,一旦这个模块被加载,之后在 python 代码里面就可以调用 py_puts 来打印字符串了。

那你可能问 py_puts 这个 c 函数又是怎么被调用的?原理很简单,因为 cpython 的解释器是用 c 写的,当用户在脚本里面调用 py_puts 的时候,解释器通过查表得到了我们之前注册到 runtime 的函数指针,之后就是 c 函数调用 c 函数了。
看你这个朋友说的语境,如果一个 c 程序用的库都是跨平台的当然没问题,简单如 hello world 这种只用 libc 的程序,甚至能在单片机上编译运行。然而任何复杂的程序不可避免要跟操作系统进行交互,形如创建进程这样常见的 api 在 windows 和 linux 上都有很大的不同,更别说文件系统结构等其他复杂问题,在 cpu 指令方面还有字长和大小端等问题。因此很多高级语言,如 python,java 是通过一个强大的标准库来屏蔽这些差异。当然,如果你说的跨平台是指程序在对应的平台上有编译器那就另说了。
1  2  3  4  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2718 人在线   最高记录 6543   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 31ms · UTC 15:30 · PVG 23:30 · LAX 08:30 · JFK 11:30
Developed with CodeLauncher
♥ Do have faith in what you're doing.