Go 编程语言最受欢迎的方面之一是它对计算机同时完成许多任务的能力的一流支持。随着计算机从较快地执行单一代码流转向同时运行许多代码流,同时运行代码的能力在编程中变得越来越重要。为了使程序运行得更快,程序员必须将其设计为同时运行,以便系统的每个并发元素可以独立于其他元素执行。
两个Go 功能,Goroutines ,和通道一起使用时,使并发变得更容易。Goroutines ,为这种能力提供了基本的原始类型。Goroutines ,在内存空间、线程间交互和网络连接方面,成本较低。它们也比线程有更好的启动时间,许多编程语言都支持。实质上,Go 指的是Goroutines ,即Java和其他编程语言所指的线程。
什么是Goroutines ?
goroutine是Golang中的一个简单的实现线程,它与程序的其他部分同时执行。Goroutines ,当类似于标准线程时,由于创建goroutine的成本极低,所以可以负担得起。因此,在Go ,它们被广泛地运用于并发编程。每个程序都至少包括一个被称为主程序(main goroutine)的goroutine。主程序控制所有其他的程序;因此,如果主程序终止,脚本中所有其他的程序也会终止。Goroutine总是在后台活动。
例子。这里有一个例子:你在笔记本上写东西,肚子饿了;你会休息一下,吃点东西。然后再开始写。你现在正在做两个角色(写作和吃东西),由一个时间窗口被认为是兼职。应该强调的是,这两项工作(写作和吃饭)仍然需要同时完成。当项目同时完成时,被称为并行性(想象一下在啃薯片时使用手机)。并发包括同时与许多事物进行交互。并行性(同时执行许多事情)是它的一个子类(不必同时执行),有一些时间表。
我们可以通过在函数调用中应用go关键字来添加一个goroutine。一旦我们将go关键字应用到功能调用中,我们将把并发性设置为性能。但是,首先,让我们确定在执行中应用go关键字的效果。让我们考虑在一个程序中有两个goroutine。文本 "package main import" 将是程序的入口。在Go 中,package main import是一个声明性的导入语句。主goroutine (first goroutine) 是隐含的。当我们执行go (f)时,第二个goroutine就形成了(0)。通常情况下,当我们执行一个函数时,我们的软件会执行主函数中的每一条命令,然后再进入下一行。
我们可以用一个goroutine快速运行程序,然后再进入下一步。因此,增加了一个scanln方法,否则,代码会在显示所有数字之前结束。Goroutines ,创建起来很简单,可能会有大量的数字。你会注意到,当这个软件运行时,goroutines似乎是按顺序运行的,而不是并发的。
与线程相比,Goroutines 的优点
Goroutines 成本低
Goroutines 比其他进程的成本低。质量大小只有几千字节,它可以扩展或收缩以满足程序的需求,与之相反,线程的堆栈大小必须被定义,而且是永久性的。
有复用的Goroutines
操作系统的线程很少有被复用的。在一个有数百个goroutine的程序中,可能只有一个进程。其余的goroutine被转移到新的操作系统进程中。假设该进程中的任何一个goroutine被卡住了,例如,当它在寻求用户干预时。运行时对这些都进行管理,而我们开发者被赋予一个清晰的API来同时管理,同时与这些微妙的错综复杂的问题隔绝。
Goroutines 使用通道进行交流
Goroutines 使用通道进行交流。旨在防止在共享相关内存时发生竞赛情况。通道可以被比喻为goroutines用来交互的管道。
什么是通道?
两个goroutines可以通过通道相互作用并协调它们的操作。这个软件会连续打印 "ping"。为了指定一个通道形式,前缀 "chan" 伴随着通道上传输的项目。"在这种情况下,我们提供的是字符串。在信道上,信息的发送和接收是使用运算符的。"ping" 指的是发送一个 "ping" 。
通道被用来保持两个goroutine的同步。在试图通过通道发送消息之前,路由器将等待,直到打印机准备好接受它。这方面的术语是抑制。当创建一个通道时,第二个参数可用于make函数。c:= make (chan int, 1)
通道的方向
我们可以定义一个通道形式的方向和参数,它可以接收或发送。例如,Pinger的方法符号可以被改变成这样。
func pinger(c chan<- string)
C现在只能被发送。从c接收将导致代码错误。同样地,我们可以将输出修改为:。
func printer(c string -chan)
一个半信道没有这些约束。一个双向通道可以提供给一个只接受只发送或只接受通道的程序,但不能反过来。
如何制作一个Goroutine?
启动一个goroutine的方法是很简单的。在函数调用中应用 "go" 关键字,使一个goroutine同时执行。这里我们要做一个goroutine。假设我们有一个包含两个函数的程序:一个是欢迎函数,另一个是主函数。
当我们创建一个新的goroutine时,欢迎()代码将与main()函数同时执行。当你执行这个程序时,你会感到惊讶。这个程序仅仅显示了主操作文本。我们启动的第一个goroutine或新goroutine发生了什么?要理解为什么会发生这种情况,我们首先要知道goroutine的两个主要特征。
- 当我们创建一个新的goroutine时,goroutine函数会立即做出反应。除了函数之外,管理层并不依赖goroutine,所以它不会等待它完成执行。执行被交给了goroutine函数之后的下一个代码块。这就是为什么任何来自goroutine的给定参数都被忽略了。
- 任何额外的goroutine应该与主goroutine同时运行。如果主goroutine失败,程序将退出,没有额外的goroutine将运行。
你现在明白为什么我们的代码不工作了。在调用go welcome()之后,在等待hello goroutine完成之前,控制权被转移到下面一行代码,主函数被输出。主goroutine死了,因为没有脚本可以执行,阻止了hello Goroutine的运行。
我们调用了sleep技术(time.sleep(1 * time.second ),将goroutine暂停了1秒钟。现在,在主goroutine退出之前,去欢迎()的函数有足够的时间来完成。这个软件最初写的是"welcome goroutine",然后在打印主函数之前等待一秒钟。我们在主goroutine中使用sleep技术,使其暂停片刻,让其他goroutine完成。
创建多个Goroutines
我们要启动另一个程序来创建多个goroutine。我们可以先创建两个将平行执行的goroutine。这两个goroutines是数字goroutines[go numbers()] 和字母goroutines [go alphabets ()]。
数字goroutine在打印1之前停留250ms,在打印2之前再次休息,以此类推,直到产生5。同样地,字母数字goroutine显示从a到e的字母,然后等待400毫秒。最后,主程序创建了整数和字母数字字符,并停顿了一下,然后主程序就终止了。
经常发生的并发编程错误
- 在需要同步的时候没有同步
- 使用时间。睡眠调用来做同步
- 让goroutine悬空复制标准同步包中的类型的值
- 调用同步
- 等待组
- 在错误的地方添加方法
- 使用通道作为明天的关闭通道,而不是从最后的功能发送者goroutine中使用
总结
在这篇文章中,我们开发了一个程序,使用go关键字来启动一个goroutine和多个goroutine,同时打印整数。在启动该程序后,我们建立了一个新的通道,然后用这个通道在一个goroutine中产生数字,并将其传递给另一个goroutine,以便在屏幕上显示。作为如何在多核系统上启动goroutine以加速你的应用程序的最后演示,你同时启动了许多 "打印 "goroutine。
正如我们所知,goroutines是一种更快速有效地执行任务的方式。这是AppMaster 所提供的部署程序之一,以改善你的应用程序的功能。通过AppMaster ,即使是几乎没有编程知识的人也可以完成通过手工编码来完成的具有挑战性的任务。
AppMaster 是一个 no-code平台,能够创建移动和网络应用 以及后台。一个有趣的事实是AppMaster ,通过Go ,以每秒22,000行的速度创建一个后台,你可以访问源代码。