首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >GO - Goroutine和并发

GO - Goroutine和并发
EN

Software Engineering用户
提问于 2017-01-31 05:06:27
回答 2查看 2.6K关注 0票数 5

背景:

线程采用抢占式调度,而C++光纤采用协同调度.使用P螺纹:当前执行路径可能在任何时候被中断或抢占--这意味着对于线程来说,数据完整性是一个大问题,因为一个线程可能会在更新数据块的过程中停止,从而使数据的完整性处于糟糕或不完整的状态。这也意味着操作系统可以利用多个CPU和CPU核心,同时运行多个线程,由开发人员来保护数据访问。使用C,int pthread_create(pthread_t *线程,const pthread_attr_t *attr,void *(*start_routine) (void *),void *arg);使用线程,应用程序可能具有并发性,并发属性: 1)多个参与者2)共享资源3)访问规则(原子/条件同步)

对于C++光纤:只有当光纤产生执行时,当前的执行路径才会被中断--这意味着光纤总是在定义良好的地方开始和停止,因此数据完整性问题要少得多。另外,由于光纤通常是在用户空间中管理的,因此不需要进行昂贵的上下文切换和CPU状态更改,从而使从一种光纤到另一种光纤的转换非常高效。另一方面,由于没有两个光纤能够同时运行,仅使用光纤并不能利用多个CPU或多CPU核心。在Win32中,光纤是一种用户管理的线程.一个光纤有它自己的堆栈和自己的指令指针等等,但是操作系统没有对光纤进行调度:您必须显式地调用SwitchToFiber。相反,线程是由操作系统预先安排的.因此,粗略地说,光纤是在应用程序/runti me级别管理的线程,而不是真正的OS线程。使用C,void __stdcall MyScheduler(void *param){ .} LPVOID *FiberScheduler = CreateFiber(0,MyScheduler,NULL);

为什么是C++纤维?OS线程为我们提供了我们想要的一切,但这是一个沉重的性能损失:线程之间的切换需要从用户跳到内核模式,甚至可能跨越地址空间边界。这些操作代价高昂,部分原因在于它们会导致TLB刷新、缓存丢失和CPU流水线破坏:这也是为什么陷阱和syscalls比常规过程调用慢几个数量级的原因。此外,内核使用通用调度算法调度线程(即将它们的延续分配给CPU核心),该算法可能会考虑所有类型的线程,从服务单个事务的线程到播放整个视频的线程。光纤,因为它们被安排在应用层,可以使用更适合其用例的调度程序。由于大多数光纤用于服务事务,它们通常在很短的时间内处于活动状态,并且经常被阻塞。它们的行为通常由IO或另一个光纤唤醒,运行一个短的处理周期,然后将控制转移到另一个光纤(使用队列或另一种同步机制),.Such行为最好由调度程序提供服务,该调度程序使用一种称为“偷工作”的算法;当光纤以这种方式运行时,偷工作确保了在光纤之间切换时丢失的缓存最小。

光纤没有利用多核的能力,因为操作系统知道的是单线程进程。

在GO中,我们使用go关键字调用goroutines

代码语言:javascript
运行
复制
func main(){
  go f() // f runs as new go routine
  f()
}

问题:

1) GO例程(f)是GO运行时在用户空间中非先发制人地调度的光纤吗?

2)如果是,围棋环境中是否会出现并发情况?

3)支持操作系统级线程的api吗?

EN

回答 2

Software Engineering用户

回答已采纳

发布于 2017-01-31 12:19:42

问题1:不完全是

戈鲁丁有点奇怪。它们有点类似于纤维,但也有点类似于线程。

  • 他们可能会被抢夺。
  • 可能是同时发生的。
  • 他们可能分享资源。
  • 他们经常阻塞队列(通道)。
  • 他们有自己的堆叠。
  • 它们不是由操作系统直接调度的,而是由golang运行时调度的。

默认情况下,golang运行时通常会启动到GOMAXPROCS线程,并将您的goroutines安排在其中。在任何给定的线程上,goroutine都会运行到完成或阻塞在通道上。

这意味着,您可以将goroutines看作线程间共享的纤维。

这意味着你可以想到那些不像你想象的那样进入全球状态的猩猩。但是对于访问全局状态的goroutines来说,您需要像线程一样对待它们。

问题2:是

在访问全局状态时,您需要注意!

然而,默认的通信机制,通道,同步访问共享资源,这大大简化了并发编程的围棋。

问题3:不在标准库中

如果你真的愿意,你可以用C语言编写一个库来启动线程,这样你就可以访问底层的OS线程函数(比如pthread_create)。

但是,我强烈怀疑您能否在以这种方式创建的线程上使用goroutines和通道,因为golang运行时调度程序不知道它们。

这也可能导致调用其他库(如标准库!)的问题!假设他们可以进入峡谷和通道。

总之,我不认为在Go中直接创建和管理线程是个好主意。

票数 3
EN

Software Engineering用户

发布于 2017-01-31 06:40:30

Goroutines是一个编译器工具。从概念上讲,Goroutines和纤维是与环境有关的协同多任务处理方法。光纤是OS级别的概念,而goroutine是编译器级的概念。

Goroutines可能与纤维规范相匹配(似乎有很多),但不一定是最严格意义上的纤维。事实上,根据调度程序的决定,大猩猩可以分布在多个线程上。

  1. 提供了纤维的解释。是的,Goroutines可以被称为是你提出的纤维规范的一个实现。
  2. 理想情况下,您应该考虑CSP,而不是并发性。

通信顺序进程(CSP)是go的并发模型,Goroutines实现了这一点。隔离戈鲁蒂部分并考虑并发性,这与金牙的观点有点不同。

我们鼓励您使用通道来维护数据流,而不依赖任何其他同步机制(正如pike所说,不要通过共享进行通信,通过通信来共享)。虽然您仍然可以使用互斥,但您仍然不能自己创建线程。

事实上,go的并发方法比其他传统语言及其实现更接近erlang。

  1. 原因和上面一样。Go不允许直接创建线程(不过,您可以生成多个进程)。我们鼓励您只使用具有通道的Goroutines,以防止混淆使用多个多任务处理方法。

Go使用与环境变量GOMAXPROCS设置的相同数量的OS线程( GO1.5设置为CPU核心计数)。

这里有一个很好的讨论

票数 6
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/341262

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档