您现在的位置是:首页 >技术杂谈 >Go 中的并发和 Goroutines:利用并发编程的力量网站首页技术杂谈

Go 中的并发和 Goroutines:利用并发编程的力量

jascl 2024-09-11 12:01:04
简介Go 中的并发和 Goroutines:利用并发编程的力量

在当今快节奏的世界中,高效并发执行多项任务的能力对于构建健壮的高性能软件系统至关重要。Go 及其内置的并发原语为开发人员提供了强大的工具来利用并发编程的潜力。在这篇文章中,我们将探讨 Go 中并发的概念,并深入研究 goroutines 的世界,这是一个使 Go 中的并发编程具有令人难以置信的表现力和效率的关键特性。

了解并发:

并发性是指程序同时执行多个任务的能力,从而能够有效利用可用资源。Go 通过其称为 goroutines 的轻量级类线程实体来支持并发。与传统线程不同,goroutines 非常轻巧,可以大量创建而不会产生任何显着的性能开销。这使得创建数千个 goroutines 以同时执行多个任务而不会显着降低性能成为可能。

协程:

Goroutines 是可以与其他 goroutines 同时执行的函数或方法。它们可以被认为是独立运行的执行单元,通过通道进行通信,这是 Go 中一种强大的通信机制。要创建一个 goroutine,我们只需要在函数或方法调用前加上关键字go
Go 运行时调度程序负责管理跨可用处理器内核的 goroutine 的执行和调度。

让我们看一个简单的例子来理解 goroutines 是如何工作的:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">package</span> <span style="color:var(--syntax-text-color)">main</span>

<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-text-color)">(</span>
    <span style="color:var(--syntax-string-color)">"fmt"</span>
    <span style="color:var(--syntax-string-color)">"time"</span>
<span style="color:var(--syntax-text-color)">)</span>

<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">sayHello</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">i</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-text-color)">i</span> <span style="color:var(--syntax-error-color)"><</span> <span style="color:var(--syntax-literal-color)">5</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-text-color)">i</span><span style="color:var(--syntax-error-color)">++</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-text-color)">fmt</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Println</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Hello"</span><span style="color:var(--syntax-text-color)">)</span>
        <span style="color:var(--syntax-text-color)">time</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Sleep</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">100</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-text-color)">time</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Millisecond</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">sayWorld</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">i</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-text-color)">i</span> <span style="color:var(--syntax-error-color)"><</span> <span style="color:var(--syntax-literal-color)">5</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-text-color)">i</span><span style="color:var(--syntax-error-color)">++</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-text-color)">fmt</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Println</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"World"</span><span style="color:var(--syntax-text-color)">)</span>
        <span style="color:var(--syntax-text-color)">time</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Sleep</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">100</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-text-color)">time</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Millisecond</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">}</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">go</span> <span style="color:var(--syntax-text-color)">sayHello</span><span style="color:var(--syntax-text-color)">()</span>
    <span style="color:var(--syntax-declaration-color)">go</span> <span style="color:var(--syntax-text-color)">sayWorld</span><span style="color:var(--syntax-text-color)">()</span>

    <span style="color:var(--syntax-comment-color)">// Wait for goroutines to finish</span>
    <span style="color:var(--syntax-text-color)">time</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Sleep</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">1</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-text-color)">time</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Second</span><span style="color:var(--syntax-text-color)">)</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

在上面的示例中,我们有两个函数,sayHellosayWorld,它们作为 goroutines 同时执行。sayHello 函数打印了五次“Hello”,而 sayWorld 函数打印了五次“World”。通过并发执行它们,我们可以在控制台中观察到“Hello”和“World”的交错输出。

同步和通信:

虽然 goroutines 支持并发执行,但它们之间的适当同步和通信对于避免数据竞争和确保一致的结果至关重要。Go 提供通道,一种安全传递数据和同步 goroutines 的机制。通道可用于在 goroutine 之间发送和接收值,允许它们进行通信和协调它们的操作。

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-declaration-color)">package</span> <span style="color:var(--syntax-text-color)">main</span>

<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-text-color)">(</span>
    <span style="color:var(--syntax-string-color)">"fmt"</span>
    <span style="color:var(--syntax-string-color)">"time"</span>
<span style="color:var(--syntax-text-color)">)</span>

<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">printMessage</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">message</span> <span style="color:var(--syntax-declaration-color)">string</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">ch</span> <span style="color:var(--syntax-declaration-color)">chan</span> <span style="color:var(--syntax-declaration-color)">bool</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">for</span> <span style="color:var(--syntax-text-color)">i</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-literal-color)">0</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-text-color)">i</span> <span style="color:var(--syntax-error-color)"><</span> <span style="color:var(--syntax-literal-color)">5</span><span style="color:var(--syntax-text-color)">;</span> <span style="color:var(--syntax-text-color)">i</span><span style="color:var(--syntax-error-color)">++</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-text-color)">fmt</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Println</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-text-color)">message</span><span style="color:var(--syntax-text-color)">)</span>
        <span style="color:var(--syntax-text-color)">time</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Sleep</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-literal-color)">100</span> <span style="color:var(--syntax-error-color)">*</span> <span style="color:var(--syntax-text-color)">time</span><span style="color:var(--syntax-error-color)">.</span><span style="color:var(--syntax-text-color)">Millisecond</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-text-color)">}</span>
    <span style="color:var(--syntax-text-color)">ch</span> <span style="color:var(--syntax-error-color)"><-</span> <span style="color:var(--syntax-declaration-color)">true</span> <span style="color:var(--syntax-comment-color)">// Notify that the goroutine has completed</span>
<span style="color:var(--syntax-text-color)">}</span>

<span style="color:var(--syntax-declaration-color)">func</span> <span style="color:var(--syntax-text-color)">main</span><span style="color:var(--syntax-text-color)">()</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-text-color)">ch</span> <span style="color:var(--syntax-error-color)">:=</span> <span style="color:var(--syntax-text-color)">make</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">chan</span> <span style="color:var(--syntax-declaration-color)">bool</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-comment-color)">// Create a channel for synchronization</span>

    <span style="color:var(--syntax-declaration-color)">go</span> <span style="color:var(--syntax-text-color)">printMessage</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"Hello"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">ch</span><span style="color:var(--syntax-text-color)">)</span>
    <span style="color:var(--syntax-declaration-color)">go</span> <span style="color:var(--syntax-text-color)">printMessage</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-string-color)">"World"</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">ch</span><span style="color:var(--syntax-text-color)">)</span>

    <span style="color:var(--syntax-comment-color)">// Wait for both goroutines to finish</span>
    <span style="color:var(--syntax-error-color)"><-</span><span style="color:var(--syntax-text-color)">ch</span>
    <span style="color:var(--syntax-error-color)"><-</span><span style="color:var(--syntax-text-color)">ch</span>
<span style="color:var(--syntax-text-color)">}</span>
</code></span></span>

在这个例子中,我们有一个 printMessage 函数,它接受一个消息字符串和一个通道 ch 作为参数。在函数内,消息被打印五次,每次打印语句之间有一个小的延迟。完成执行后,它会向通道发送一个真值以表示它已完成。

在 main 函数中,我们使用 make 函数创建一个通道 ch。然后,我们使用 go 关键字启动两个 goroutine,每个 goroutine 执行带有不同消息(“Hello”和“World”)的 printMessage 函数并共享相同的通道 ch。

为了确保同步并等待 goroutines 完成,我们使用通道操作<-ch。操作<-ch阻塞,直到从通道接收到值。通过两次执行此操作,我们确保在程序退出之前两个 goroutine 都已完成。

通过使用通道 ch,goroutines 进行通信和协调它们的动作。他们轮流打印各自的消息,导致在控制台中交错输出“Hello”和“World”。

这个例子演示了如何使用通道来同步 goroutines,允许它们进行通信和协调它们的活动,从而避免数据竞争并确保并发程序中的结果一致。

结论:

并发和 goroutines 是 Go 的强大功能,可实现高效且富有表现力的并发编程。通过利用 goroutines 和通道,开发人员可以构建高性能和可扩展的系统,充分利用现代硬件功能。理解并发原理并有效地使用 goroutines 可以使开发人员编写出不仅高效而且更易于推理和维护的并发代码。

所以,如果你想在你的 Go 程序中拥抱并发的力量,试试 goroutines,开启一个高度并发和高效的软件开发世界。编码愉快!

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。