目次
Go の goroutine とチャネルについて話しましょう
#1.ゴルーチン" >#1.ゴルーチン
# チャネルをパラメータとして渡す" ># チャネルをパラメータとして渡す
#チャンネルは閉鎖されました" >#チャンネルは閉鎖されました
ホームページ バックエンド開発 Golang Go の同時プログラミングについて話しましょう (1)

Go の同時プログラミングについて話しましょう (1)

Jul 07, 2021 pm 04:13 PM
go

Go の goroutine とチャネルについて話しましょう

  • 序文
  • 1. Goroutine
    • 定義
    • まず goroutine の使い方を知るためにケースを見てください
    • それは何ですか
  • 2. チャネル
    • 基本的な使い方
    • チャネルをパラメータとして渡す
    • 複数のチャネルを作成する
    • チャネルを戻り値として使用する
    • バッファ チャネル
    • チャネル クローズ

    おすすめ関連記事: 「 Go の同時プログラミングの話 (2)

    ##まえがき

##以前 Go 言語を学習していたとき、Groutin と Channel を見たときにスキップしてしまいました。

当時はまったく真剣に考えていませんでしたが、なぜそんなに複雑だと思いますか? (当時の心境)

最近goの同時プログラミングを調べていたら、全部この内容を使っていることが分かり、仕方なく噛んでみました。弾丸ですが、見てみると、それほど難しいものではないことがわかります。

見たくないものを先に置いて、注意を集中してから見ると、思わぬ利益が得られることがあります。

今日の記事は簡単な説明です。カカさんも囲碁コースに登録しています。どのコースを見れば理解が深まりますか?続きはまた後ほど。深さを追加しました。 。

##定義

#関数の前に go を追加するだけです。
    定義上、非同期関数かどうかを区別する必要はありません。
  • 適切な時点でスケジューラが切り替わります。ポイントはたくさんあります。 , ここはあくまで参考であり、切り替わる保証はありませんし、他のところで切り替わらないという保証もありません。 IO 操作、チャネル、ロックの待機、関数呼び出し、runtime.Gosched() など。 。 。
  • race を使用してデータ アクセスの競合を検出する
まずケースを見て goroutine の使用方法を確認してください

最初にケースを見てみましょう

Go の同時プログラミングについて話しましょう (1)

##このケースは、単純な同時実行コードです。その中のキーワードは 1 つだけです。「go」です。

それでは、このコードが何を出力するかを見てみましょう

Go の同時プログラミングについて話しましょう (1)

上の図からわかるように、このコード行は何も出力せず、直接終了します。

直接終了する理由は、コード内の main と fmt の出力が同時に実行されるためです。fmt がデータが来る前に緊急にデータを出力する場合、外側のループはすでに終了しています。直接出た。

Go 言語で! main 関数が終了した後、すべてのゴルーチンを直接 kill することを想定しているため、ゴルーチンが来る前に緊急の印刷データが返されるという現象が発生します。

それでは、印刷されたデータをどのように確認できるか疑問に思われていますか?実際、これは非常に簡単で、main 関数の実行後に急いで終了せず、しばらく待つだけです。ケースを見てください。

Go の同時プログラミングについて話しましょう (1)

#今回の目的の結果が表示されます。

この場合、オープンされるゴルーチンの数は 10 ですが、これを 1000 に変更するとどうなりますか?

結果表示は、1,000 人が同時に印刷しているのと同じように、引き続き正常に表示されます。

では、設定 10 と 1000 にはどのような関係があるのでしょうか?

オペレーティング システムに詳しい人なら、10 個のスレッドを開いても問題はなく、100 個のスレッドを開いても大きな問題はなく、ほぼ十分であることがわかるはずです。

一般に、システムは数十のスレッドを開くことができますが、1,000 人が同時に 1 つのことを実行する必要がある場合、スレッドを使用して問題を解決することはできず、非同期メソッドを使用する必要があります。が必要です。

#しかし、Go 言語では! go キーワードを直接使用するだけで、同時に実行できます。

次に、なぜ go が同時に 1000 件も印刷できるのかについて説明します。

とはまず、コルーチンとスレッドの違いを見てみましょう。

コルーチンは、軽量スレッド非プリエンプティブ マルチタスク、コルーチンは制御権をアクティブに引き継ぎますとして理解できます。

スレッドはいつでもオペレーティング システムによって切り替えられるため、スレッドはプリエンプティブ マルチタスクであることを誰もが知っておく必要があります。ステートメントが実行された場合でも、スレッドには制御がありません。スレッドの半分は実行されます。オペレーティング システムによって切断され、操作のために他のスレッドに転送されます。

逆に、コルーチンの場合、いつ制御権を渡すか、いつ制御権を渡さないかは、コルーチンによって内部的に能動的に決定されます。プリエンプション式なので軽量と呼ばれます。

そして 複数のコルーチンは 1 つ以上のスレッドで実行できます

2. チャンネル

最初のセクションでは、多くのゴルーチンを go で開くことができることを学びました。そのため、ゴルーチン間の双方向チャネルは channel

Go の同時プログラミングについて話しましょう (1)

基本的な使い方

Go の同時プログラミングについて話しましょう (1)

##上の図よりこの場合、make 関数を直接使用してチャネルを作成できることがわかります。

7 行目と 8 行目は、チャネルにデータを送信します。

#それでは、この事件は実行できるでしょうか?試してみよう######

Go の同時プログラミングについて話しましょう (1)

#この時点でエラーが報告されていることがわかりますが、このエラーはチャネルに 1 を送信するときにデッドロックが発生することを意味します。

次に、前の図に戻ります。

Go の同時プログラミングについて話しましょう (1)

上で述べたように、チャネルは goroutine と goroutine の間の相互作用です。

ただし、この場合、不足している goroutine は 1 つだけなので、それを受け取るには別の goroutine が必要です。

これで、Goroutine の開始方法がわかるはずです。

Go の同時プログラミングについて話しましょう (1)

上の図では、新たに別の goroutine を開き、無限ループを使用してチャネルから送信された値を受け入れ、出力しました。 。

しかし、チャネルには 2 つのデータを送信しましたが、このときの印刷結果は 1 つのデータしかないことがわかります。でも、最初のものよりは良くなりましたね!

では、なぜこのようなことが起こるのでしょうか?

コードの実行フローは、まずチャネルに 1 が送信され、ループで最初の値が取得されて出力されることがわかります。

次に、データ 2 をチャネルに送信しますが、印刷する直前に終了します。その結果、データ 1 だけが表示され、データ 2 が表示されない現象が発生します。

Kaka の説明を読めば、この問題の解決方法がすでにわかるはずです。

つまり、関数channelDomeに遅延終了時間を追加することです。

Go の同時プログラミングについて話しましょう (1)

上でわかるように、 go の後にクロージャ関数が続きます。このクロージャで使用される c は、使用される外側の c です。

それでは、パラメータを使用してこの c を渡すことは可能でしょうか?答えは「はい」です。

Go の同時プログラミングについて話しましょう (1)

# もちろん、他のパラメータも渡すことができます

Go の同時プログラミングについて話しましょう (1)

上の図から、チャネルだけでなく id パラメータも渡され、コードを直接最適化することもできることがわかります。囲まれた部分、つまりチャネルから値を直接取得します。

複数のチャネルを作成する

Go の同時プログラミングについて話しましょう (1)

From As上図のように、全員が自分のチャンネルを持って配信し、配信後は全員が自分の受信値を受け取り、出力します。

同様に、チャネルにデータを送信するために 26 行目に新しい for ループを追加していることがわかります。

Go の同時プログラミングについて話しましょう (1)

実行結果から、receive i と accept I の 2 つの値が表示されるなど、出力順序が混乱していることがわかります。

現時点で何か疑問がありますか? チャネルにデータを送信するときは、順番に送信します。次に、受信時に順番に受信する必要があります。

データは順番に送信されていると確信しているため、この問題は Printf でのみ発生する可能性があります。

Printf には IO があり、ゴルーチンでスケジュールされているため、この時点の Printf は故障していますが、受信した値は 1 つずつ出力されます。

チャネルを戻り値として使用する

前のセクションのケースはすべてチャネルによって作成され、使用されます。渡されるパラメータとして。

次に、このセクションは戻り値としてチャネルを返します。

Go の同時プログラミングについて話しましょう (1)

ソースコード

package mainimport (
	"fmt"
	"time")func createWorker(id int) chan int {
	c := make(chan int)
	go func() {
		for {
			fmt.Printf("Worker %d receive %c\n", id, 

ここから、次のことがわかります。この関数内でチャネルが直接作成されるため、この関数は createWorker 関数に変更されました。

次に、チャネルによって受信された値がコルーチンを通じて出力されます。

#チャンネルを返します。

実行結果を見てみましょう

Go の同時プログラミングについて話しましょう (1)

実行結果から、コードの記述がまだ正しいことがわかりますが、この時点で返されたチャネルの使用方法が非常に直感的にわかることがわかります。

しかしコードの数が大きい場合、このチャネルの使用方法がまったくわからないため、このコードすべてを単純に変更する必要があります。

では、外部の人に使い方を伝える必要があります。

Go の同時プログラミングについて話しましょう (1)

上記のコードから、データがチャネルに送信され、その後 createWorker# で送信されることがわかります。 # #メソッドによって返されるチャネルには、

Go の同時プログラミングについて話しましょう (1)

# とマークする必要があります。

現在のコードは次のようになり、createWorker メソッドの戻り値チャネルの方向を直接マークします。機能はデータを送信することです。

次に、印刷すると、それが領収書になるため、非常に直感的に見えます。

上記の 2 つの手順を変更すると、createWorker がエラーを呼び出すことがわかります。Cannot use 'createWorker(i)' (type chanエラーが表示されると、2 つの型が等しくないことがわかります。

Go の同時プログラミングについて話しましょう (1)

#修正後は、コンパイルが正しく行われ、エラー メッセージが報告されないことがわかります。

Go の同時プログラミングについて話しましょう (1)也是ok的。

Go の同時プログラミングについて話しましょう (1)

本小节源码

package mainimport (
	"fmt"
	"time")func createWorker(id int) chan

buffer channel

学习了这么久了,那么咔咔问你一个问题,这段代码执行会发生什么?

Go の同時プログラミングについて話しましょう (1)

はい、記事の冒頭で述べたように、チャネルにデータを送信するには、別のコルーチンを開いてデータを受信する必要があるため、エラーが発生します。

コルーチンは軽量と言われていますが、データを送信した後、データを受信するためにコルーチンを切り替える必要があり、非常にリソースを消費します。

それでは、このセクションではこれについて説明します。

buffer channel

3 つのバッファを持つことができるチャネルを作成し、3 つのデータをそのチャネルに送信します。

同時に実行した結果から、デッドロックが発生していないこともわかります。

あなたに質問です。データ 4 をバッファに送信するとどうなりますか?

Go の同時プログラミングについて話しましょう (1)

あなたは賢いです、結果を考えたはずです、はい、報告しましたデッドロック

次に、前のワーカーを使用してチャネル データを受信します。

Go の同時プログラミングについて話しましょう (1)

しかし、実行結果では、送信された 1、2、3、4 が出力されないことがわかります。 。

この質問はこれまでに何度も聞かれていますが、この状況をどのように解決すべきかを自問してみてください。

Go の同時プログラミングについて話しましょう (1)

遅延時間を追加するだけです ちなみに、前の例では文字が出力されたことを説明したいと思います。 、%c はすべての書式設定に使用されますが、数値を出力するようになったので、%d に変更されました。これは小さな変更です。

この方法でチャネルを確立すると、パフォーマンスの向上に一定の効果があります。

これまでに問題を発見しましたか。つまり、チャネルを送信するときに、いつ送信されたかわからないという問題です。

次に、この問題を見てみましょう。

#チャンネルは閉鎖されました

前のケースからコードを借用して説明を続けます。

Go の同時プログラミングについて話しましょう (1)
前のコードと矛盾するのは、最後に close を追加したことです。close は送信側でクローズされることに注意してください。

1、2、3、4 は受信されていますが、実行結果が満足のいくものではないことがわかります。

ただし、以下では多数の 0 が受信されましたが、スクリーンショットにキャプチャされたデータは 1 つだけでした。

送信者がチャネルを閉じても、ワーカーはチャネルが閉じられてもデータを受信します。これは、チャネルが閉じられた後にデータが受信されなくなるという意味ではありません。

しかし、送信者がチャネルを閉じるように設定すると、受信したデータはすべて 0 になります。つまり、ワーカー メソッドによって渡されるパラメータ c chan int の値は 0 になります。

これで、チャネルの型は int になり、0 を受け取ります。次に、文字列型の場合、受信されるのは空の文字列です。

これにはどのくらい時間がかかりますか?それが私たちが設定した 1 ミリ秒の時間です。

このプログラムを変更するように頼まれた場合、何かアイデアはありますか?わからない場合は、このクリックのリズムに合わせて揺れてください。

Go の同時プログラミングについて話しましょう (1)

#関数ワーカーでは、受信に 2 つの値が使用されます。n は渡されるチャネル c です。 ok は、値が存在するかどうかを判断することです。

実行結果が表示され、0 データを受信することはなくなります。

この書き方以外にも、もっと簡単な方法があります。

Go の同時プログラミングについて話しましょう (1)

学習への粘り強さ、執筆への粘り強さ、そして共有への粘り強さは、Kaka が設立以来常に堅持してきた信念です。巨大なインターネット上の Kaka の記事が少しでもお役に立てれば幸いです。カカです、また会いましょう。

以上がGo の同時プログラミングについて話しましょう (1)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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

ホットAIツール

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の 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でログインするためのベストプラクティスは何ですか? Aug 04, 2025 pm 04:48 PM

構造化されたロギング、コンテキストの追加、ログレベルの制御、ロギングに敏感なデータの回避、一貫したフィールド名の使用、正確にロギングエラー、パフォーマンス、中央監視ログ、統合構成は、効率的なロギングを実現するためのベストプラクティスです。まず、JSON形式の構造化されたログ(Uber-Go/ZAPまたはRS/Zerologの使用など)が、エルク、DataDOG、およびその他のツールの解析と統合を促進します。第二に、IDやユーザーIDなどのコンテキスト情報を要求することにより、ログのトレーサビリティが強化され、Context.ContextまたはHTTPミドルウェアを介して注入できます。第三に、デバッグ、情報、警告、エラーレベルを合理的に使用し、環境変数を介して動作します。

GOサービスを優雅にシャットダウンする方法は? GOサービスを優雅にシャットダウンする方法は? Aug 05, 2025 pm 08:21 PM

usesignal.notify()tolistenforsigint/sigtermandtriggershutdown;

現在の時間を取得する方法 現在の時間を取得する方法 Aug 06, 2025 am 11:28 AM

usetime.now()togetthecurrentlocaltimeasatime.timeobject; 04:05 "; 3.getutctimeByCallingutc()ontheresultoftime.now();

GOでXMLデータを解析する方法 GOでXMLデータを解析する方法 Aug 05, 2025 pm 07:24 PM

XMLデータの解析は非常に簡単です。内蔵エンコーディング/XMLパッケージを使用するだけです。 1. XMLタグを使用して構造を定義して、XML要素とXMLなどの属性をマップします。 2. XML.UnmarShalを使用して、XML文字列を構造に解析します。 3。ファイルを使用して、os.openを使用してそれらを開き、xml.newdecoderを介してそれらをデコードします。これは、大きなファイルのストリーミング処理に適しています。 4。構造内の複製要素を処理する場合

パフォーマンスのコードをどのようにプロファイルしますか? パフォーマンスのコードをどのようにプロファイルしますか? Aug 05, 2025 am 08:50 AM

GOコードパフォーマンス分析は、組み込みのPPROFツールを介して実装できます。まず、デバッグエンドポイントをインポートして、\ _ "net/http/pprof"を有効にします。 1。HTTPサービスの場合、プログラムでLocalHost:6060のPPROFインターフェイスを開始します。 2. gotoolpprof http:// localhost:6060/debug/pprof/profile?seconds = 30を使用して、30秒CPUパフォーマンスデータを収集します。 3. gotoolpprof http:// localhost:6060/debug/pprof/heapを介してメモリ割り当てを分析します。 4.実行を有効にします

GOおよびクラウド機能を使用してサーバーレスAPIを構築します GOおよびクラウド機能を使用してサーバーレスAPIを構築します Aug 05, 2025 pm 01:21 PM

サーバーレスAPIを構築するには、GO環境をセットアップしてGoogleCloudSDKをインストールし、リクエストを処理するためにHTTP関数を書き込み、最後にGCLOUDCLIを介してCloudFunctionsに展開する必要があります。 1. go1.18とgooglecloudsdkをインストールし、プロジェクトを構成します。 2. GOモジュールを作成し、HTTP処理機能を作成し、メソッドをサポートしてポストし、JSON入力を処理し、応答を返します。 3.コードを簡素化し、ハンドラー関数のみを保持し、ローカルサーバーロジックを削除します。 4. gcloudコマンドを使用して関数を展開し、ランタイム、エントリポイント、トリガーメソッドを指定します。 5。APIのGet and Postインターフェイスをテストし、返品を確認します

GOでカスタムエラータイプを作成および使用する方法 GOでカスタムエラータイプを作成および使用する方法 Aug 11, 2025 pm 11:08 PM

GOでは、カスタムエラータイプを作成して使用すると、エラー処理の表現力とデブガブルが向上します。答えは、エラー()メソッドを実装する構造を定義することにより、カスタムエラーを作成することです。たとえば、ValidationErrorにはフィールドとメッセージフィールドが含まれ、フォーマットされたエラー情報を返します。次に、関数でエラーを返すことができ、異なるロジックを実行するために、タイプアサーションまたはエラーを使用して特定のエラータイプを検出できます。また、構造化されたデータ、差別化処理、ライブラリエクスポート、またはAPI統合を必要とするシナリオに適したカスタムエラーに適したカスタムエラーなどの行動方法を追加することもできます。単純な場合、error.new、およびerrnotfoundなどの事前定義されたエラーを使用して、比較可能にすることができます

GOアプリケーションでロギングを実行する方法は? GOアプリケーションでロギングを実行する方法は? Aug 04, 2025 pm 03:48 PM

標準のライブラリログパッケージの使用は、単純なシナリオに適していますが、ログレベルと構造化されたサポートがありません。 2。GO1.21は、ほとんどの最新のアプリケーションに適した構造化されたログと複数のプロセッサをサポートするビルトインスローを使用することをお勧めします。 3. ZAPは、非常に速い処理速度と豊富な機能を備えた高性能生産環境の最初の選択肢です。 4.新しいプロジェクトで積極的に維持されなくなったLogrusを使用しないでください。 GOバージョン、パフォーマンス要件、および構造化されたログが必要かどうかに基づいて、適切なライブラリを選択する必要があり、スローまたはZAPを優先する必要があります。

See all articles