目次
Goroutine
チャネル
ch := make(chan int, 1)
ログイン後にコピー
" >channel# and accept ##
ch := make(chan int, 1)
ログイン後にコピー
channel 的关闭
小结
ホームページ バックエンド開発 Golang Go 言語での Goroutine とチャネルの予備調査

Go 言語での Goroutine とチャネルの予備調査

Feb 02, 2023 pm 08:18 PM
golang 言語を移動

この記事では、Go 言語の Goroutine とチャネルについて予備的に理解することができます。

Go 言語での Goroutine とチャネルの予備調査

Go 言語の CSP 同時実行モデルの実装には、2 つの主要コンポーネントが含まれています。1 つは Goroutine で、もう 1 つはチャンネル。この記事ではその基本的な使い方と注意点を紹介します。

Goroutine

Goroutine は、Go アプリケーションの基本的な実行ユニットであり、軽量のユーザーレベルのスレッドです。 、最下層は coroutine (コルーチン) によって実現される同時実行です。ご存知のとおり、コルーチンはユーザー モードで実行されるユーザー スレッドであるため、Go プログラムの実行中に Goroutine もスケジュールされます。

#基本的な使い方

構文: go function/method

go キーワード function/method を通じて ## を作成できます#ゴルーチン

コード例:

import (
   "fmt"
   "time"
)

func printGo() {
   fmt.Println("具名函数")
}

type G struct {
}

func (g G) g() {
   fmt.Println("方法")
}

func main() {
   // 基于具名函数创建 goroutine
   go printGo()
   // 基于方法创建 goroutine
   g := G{}
   go g.g()
   // 基于匿名函数创建 goroutine
   go func() {
      fmt.Println("匿名函数")
   }()
   // 基于闭包创建 goroutine
   i := 0
   go func() {
      i++
      fmt.Println("闭包")
   }()
   time.Sleep(time.Second) // 避免 main goroutine 结束后,其创建的 goroutine 来不及运行,因此在此休眠 1 秒
}
ログイン後にコピー

実行結果:

闭包
具名函数
方法
匿名函数
ログイン後にコピー

複数の

Goroutine

が存在する場合、実行順序は固定されません。したがって、印刷するたびに結果が異なります。 コードからわかるように、

go

キーワードを使用して、名前付き関数 / に基づいて groutin を作成できます。 MethodGoroutine匿名関数 /closures に基づいて作成できます。 それでは、

Goroutine

はどのようにして終了するのでしょうか?通常の状況では、Goroutine 関数の実行が終了するか、実行が戻る限り、それは Goroutine の終了を意味します。 Goroutine の関数またはメソッドに戻り値がある場合、Goroutine が終了すると無視されます。

channel

channel

は、Go 同時実行モデルにおいて重要な役割を果たします。これは、Goroutine 間の通信を実装するために使用でき、また、Goroutine 間の同期を実装するためにも使用できます。

channel の基本操作

#channel

は複合データ型のため、宣言時に channel 内の要素を指定する必要があります。 ### タイプ。 宣言構文: var ch chan string

上記のコードを通じて、要素タイプが

string
である

channel を宣言します。 string 型の要素のみを保存できます。 channel は参照型であり、データを書き込むために初期化する必要があります。make によって初期化されます。

import (
   "fmt"
)

func main() {
   var ch chan string
   ch = make(chan string, 1)
   // 打印 chan 的地址
   fmt.Println(ch)
   // 向 ch 发送 "Go" 数据
   ch <- "Go"
   // 从 ch 中接收数据
   s := <-ch
   fmt.Println(s) // Go
}
ログイン後にコピー
ch <- xxx

を通じて、

x := < を介して channel 変数 ch にデータを送信できます。 ;- ch データは channel 変数 ch から受信できます。 バッファ付きチャネルとバッファなしチャネル

チャネル

の初期化時に容量が指定されていない場合は、バッファなし ##チャネルが作成されます。

: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>ch := make(chan string)</pre><div class="contentsignin">ログイン後にコピー</div></div>バッファリングされていない channel の送信操作と受信操作は同期しています。送信操作が実行されると、対応する

Goroutine

がブロックされます。受信操作を実行する別の Goroutine があり、その逆も同様です。送信操作と実行操作を同じゴルーチンの下に置くとどうなるでしょうか?次のコードを見てください: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>import ( &quot;fmt&quot; ) func main() { ch := make(chan int) // 发送数据 ch &lt;- 1 // fatal error: all goroutines are asleep - deadlock! // 接收数据 n := &lt;-ch fmt.Println(n) }</pre><div class="contentsignin">ログイン後にコピー</div></div> プログラムを実行すると、ch <-

致命的エラー

が発生し、すべての Goroutine にプロンプ​​トが表示されます。 休止状態では、デッドロック状態になります。この状況を回避するには、channel の送受信操作を別の Goroutine で実行する必要があります。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>import ( &quot;fmt&quot; ) func main() { ch := make(chan int) go func() { // 发送数据 ch &lt;- 1 }() // 接收数据 n := &lt;-ch fmt.Println(n) // 1 }</pre><div class="contentsignin">ログイン後にコピー</div></div> 上記の例から結論付けることができます: バッファリングされていない channel の送信および受信操作は 2 つの異なる

Goroutine

で実行する必要があります。そうしないと、発生しますデッドロック画像。 容量が指定されている場合、バッファ付き channel

が作成されます:
ch := make(chan string, 5)
ログイン後にコピー

バッファ付き channel およびバッファなし

chennel

は異なります。送信操作を実行するとき、channel のバッファーがいっぱいでない限り、バッファーがいっぱいになるまで Goroutine はハングしません。送信操作を実行すると、Goroutine がハングします。コード例: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>func main() { ch := make(chan int, 1) // 发送数据 ch &lt;- 1 ch &lt;- 2 // fatal error: all goroutines are asleep - deadlock! }</pre><div class="contentsignin">ログイン後にコピー</div></div>両方とも送信できるチャネルの送信専用タイプと受信専用タイプを宣言します

channel# and accept ##
ch := make(chan int, 1)
ログイン後にコピー

    channel
  • 変数は上記のコードを通じて取得され、それに対して送受信操作を実行できます。

    channel

    ch := make(<-chan int, 1)
    ログイン後にコピー

  • channel
  • 変数は上記のコードを通じて取得されており、受信のみが可能です。

    送信のみ

    channel

    ch := make(chan<- int, 1)
    ログイン後にコピー

  • channel
  • 変数は上記のコードを通じて取得され、送信のみ可能です。

通常只发送 channel 类型和只接收 channel 类型,会被用作函数的参数类型或返回值:

func send(ch chan<- int) {
   ch <- 1
}

func recv(ch <-chan int) {
   <-ch
}
ログイン後にコピー

channel 的关闭

通过内置函 close(c chan<- Type),可以对 channel 进行关闭。

  • 在发送端关闭 channel

    channel 关闭之后,将不能对 channel 执行发送操作,否则会发生 panic,提示 channel 已关闭。

    func main() {
       ch := make(chan int, 5)
       ch <- 1
       close(ch)
       ch <- 2 // panic: send on closed channel
    }
    ログイン後にコピー
  • 管道 channel 之后,依旧可以对 channel 执行接收操作,如果存在缓冲区的情况下,将会读取缓冲区的数据,如果缓冲区为空,则获取到的值为 channel 对应类型的零值。

    import "fmt"
    
    func main() {
       ch := make(chan int, 5)
       ch <- 1
       close(ch)
       fmt.Println(<-ch) // 1
       n, ok := <-ch
       fmt.Println(n)  // 0
       fmt.Println(ok) // false
    }
    ログイン後にコピー
  • 如果通过 for-range 遍历 channel 时,中途关闭 channel 则会导致 for-range 循环结束。

  • 小结

    本文首先介绍了 Goroutine的创建方式以及其退出的时机是什么。

    其次介绍了如何创建 channel 类型变量的有缓冲与无缓冲的创建方式。需要注意的是,无缓冲的 channel 发送与接收操作,需要在两个不同的 Goroutine 中执行,否则会发送 error

    接下来介绍如何定义只发送和只接收的 channel 类型。通常只发送 channel 类型和只接收 channel 类型,会被用作函数的参数类型或返回值。

    最后介绍了如何关闭 channel,以及关闭之后的一些注意事项。

    【相关推荐:Go视频教程编程教学

    以上がGo 言語での Goroutine とチャネルの予備調査の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

GOの浮動小数点番号操作に使用されるライブラリは何ですか? GOの浮動小数点番号操作に使用されるライブラリは何ですか? Apr 02, 2025 pm 02:06 PM

GO言語の浮動小数点数操作に使用されるライブラリは、精度を確保する方法を紹介します...

Go's Crawler Collyのキュースレッドの問題は何ですか? Go's Crawler Collyのキュースレッドの問題は何ですか? Apr 02, 2025 pm 02:09 PM

Go Crawler Collyのキュースレッドの問題は、Go言語でColly Crawler Libraryを使用する問題を調査します。 �...

GO言語の「VAR」と「タイプ」キーワード定義構造の違いは何ですか? GO言語の「VAR」と「タイプ」キーワード定義構造の違いは何ですか? Apr 02, 2025 pm 12:57 PM

GO言語で構造を定義する2つの方法:VARとタイプのキーワードの違い。構造を定義するとき、GO言語はしばしば2つの異なる執筆方法を見ます:最初...

Goでは、Printlnとstring()関数を備えた文字列を印刷すると、なぜ異なる効果があるのですか? Goでは、Printlnとstring()関数を備えた文字列を印刷すると、なぜ異なる効果があるのですか? Apr 02, 2025 pm 02:03 PM

Go言語での文字列印刷の違い:printlnとstring()関数を使用する効果の違いはGOにあります...

GOのどのライブラリが大企業によって開発されていますか、それとも有名なオープンソースプロジェクトによって提供されていますか? GOのどのライブラリが大企業によって開発されていますか、それとも有名なオープンソースプロジェクトによって提供されていますか? Apr 02, 2025 pm 04:12 PM

大企業または有名なオープンソースプロジェクトによって開発されたGOのどのライブラリが開発されていますか? GOでプログラミングするとき、開発者はしばしばいくつかの一般的なニーズに遭遇します...

Golandのカスタム構造ラベルが表示されない場合はどうすればよいですか? Golandのカスタム構造ラベルが表示されない場合はどうすればよいですか? Apr 02, 2025 pm 05:09 PM

Golandのカスタム構造ラベルが表示されない場合はどうすればよいですか?ゴーランドを使用するためにGolandを使用する場合、多くの開発者はカスタム構造タグに遭遇します...

Redisストリームを使用してGO言語でメッセージキューを実装する場合、user_idタイプの変換の問題を解決する方法は? Redisストリームを使用してGO言語でメッセージキューを実装する場合、user_idタイプの変換の問題を解決する方法は? Apr 02, 2025 pm 04:54 PM

redisstreamを使用してGo言語でメッセージキューを実装する問題は、GO言語とRedisを使用することです...

Golang Generic Function Typeの制約がVSCodeで自動的に削除されるという問題を解決する方法は? Golang Generic Function Typeの制約がVSCodeで自動的に削除されるという問題を解決する方法は? Apr 02, 2025 pm 02:15 PM

VSCODEユーザーのGolang Generic Function Typeの制約の自動削除は、VSCODEを使用してGolangコードを書くときに奇妙な問題に遭遇する可能性があります。いつ...

See all articles