标签:布局 epo lan 复杂 需求 线程 处理 func 基于
Go是现代编程语言领域中最新加入的语言之一。Go自诩为“一种开源编程语言,可以轻松构建简单、可靠和高效的软件”。Go使开发人员能够以简洁、简单和安全的方式构建健壮和高效的软件。找到一个优秀的围棋开发人员不仅仅需要找到一个好的程序员,还需要找到一个理解这门语言、它的习惯用语等等的人
Go调度器的设计和行为允许您的多线程Go程序更高效和性能。这要感谢Go调度器对操作系统(OS)调度器的机制支持。然而,如果你的多线程Go软件的设计和行为与调度器的工作方式在机械上不一致,那么这些都无关紧要。对于OS和Go调度器如何正确设计多线程软件,有一个一般性和代表性的理解是很重要的。
操作系统调度器是复杂的软件。他们必须考虑他们所运行的硬件的布局和设置。这包括但不限于多个处理器和核心、CPU缓存和NUMA的存在。如果没有这些知识,调度器就不能尽可能高效。最棒的是,您仍然可以开发一个很好的心理模型,了解操作系统调度器如何工作,而不必深入研究这些主题。
你的程序只是一系列机器指令,需要一个接一个地依次执行。
多个线程可以属于同一个进程并共享内存空间。因为多线程不需要创建新的虚拟内存空间,所以它们也不需要内存管理单元处理上下文的切换,线程之间的通信也正是基于共享的内存进行的,与重量级的进程相比,线程显得比较轻量。
虽然线程比较轻量,但是在调度时也有比较大的额外开销。每个线程会都占用 1M 以上的内存空间,在切换线程时不止会消耗较多的内存,恢复寄存器中的内容还需要向操作系统申请或者销毁资源,每一次线程上下文的切换都需要消耗 ~1us 左右的时间1,但是 Go 调度器对 Goroutine 的上下文切换约为 ~0.2us,减少了 80% 的额外开销。
Go 语言的调度器通过使用与 CPU 数量相等的线程减少线程频繁切换的内存开销,同时在每一个线程上执行额外开销更低的 Goroutine 来降低操作系统和硬件的负载。
单线程调度器
0.x 版本调度器只包含表示 Goroutine 的 G 和表示线程的 M 两种结构,全局也只有一个线程。我们可以在 clean up scheduler 提交中找到单线程调度器的源代码,在这时 Go 语言的调度器还是由 C 语言实现的,调度函数 runtime.scheduler:9682400 也只包含 40 多行代码 :
static void scheduler(void) {
G* gp;
lock(&sched);
if(gosave(&m->sched)){
lock(&sched);
gp = m->curg;
switch(gp->status){
case Grunnable:
case Grunning:
gp->status = Grunnable;
gput(gp);
break;
...
}
notewakeup(&gp->stopped);
}
gp = nextgandunlock();
noteclear(&gp->stopped);
gp->status = Grunning;
m->curg = gp;
g = gp;
gogo(&gp->sched);
}
channel
是 Go 语言中的一个非常重要的特性。
channel是连接并发goroutine的管道。您可以将值从一个goroutine发送到channel中,并将这些值接收到另一个goroutine中。
使用make(val-type)创建一个新channel。channel是由它们传递的值来键入的。
message:= make(字符串)
使用channel道<-语法将值发送到channel中。在这里,我们从一个新的goroutine发送“ping”到我们上面创建的消息channel。
执行func() {messages <- "ping"}()
<-channel语法从channel接收一个值。在这里,我们将收到上面发送的“ping”消息并将其打印出来。
味精:= <消息
fmt.Println(味精)
}
当我们运行程序时,“ping”消息通过我们的channel成功地从一个goroutine传递到另一个goroutine
package main
import "fmt"
func main() {
messages := make(chan string)
go func() { messages <- "ping" }()
msg := <-messages
fmt.Println(msg)
}
$ go run channels.go
ping
GO是一门非常灵活的语言,能够解决很多问题。您可以将其用于系统和网络编程、大数据、机器学习、音频和视频编辑等。
软件的架构的终极目标,以及如何衡量一个架构的优劣,尤其是两个错误的观点非常感同身受,我也说过类似的话语,还有一句话是“当前的需求非常紧急,这只是一个临时的系统很快就会被替换掉,我们先完成它”。作为一个专业的技术人员我们需要有一些底线来保证我们的代码架构和质量,不能轻易妥协,这在 Bob 大叔整洁系列的另外一本书中也有提到。Go工程化
架构设计是需要考虑实现细节的,设计需要映射到代码结构和代码树上,这个其实和最开始的“软件架构师自身需要是程序员,并且必须一直坚持做一线程序员”交相呼应。
如果可以在编译时解决的问题,就不要放到运行时,编译的问题往往要比运行时的问题好解决,这也是为什么 Go 的依赖注入框架我更加推荐 wire 的原因,同理作者提出了 如果要防止直接中 web控制器调用数据层,那么我们就不应该将数据层(repo)暴露出来,只需要暴露 usecase 就好了
...
标签:布局 epo lan 复杂 需求 线程 处理 func 基于
原文地址:https://www.cnblogs.com/ffviu/p/14726740.html