golangの同時制御技術と原理(一:channel,waitgroup,context)


goの同時制御手段はchannel,waitgroup,context,syncパッケージのrwlock,lock,pool,Once,cond,mapなどが別の記事で紹介されている.
この記事では、これらの同時制御技術の使用方法と実現原理について説明します.
目次
一:channel
二:waitgroup
下層構造
方法
方法の実現原理
waitgroupの使用
注意事項
三:context
Contextインタフェース
Contextインタフェースの実装構造
対外関数
使用方法
使用仕様
使用例

一:channel


channelの使用方法と実現原理については,もう一つの文章で紹介されているが,ここではこれ以上述べない.
 
 
 

二:waitgroup


sync.WaitGroupは、キャリア間の同期ブロック待ちの問題を解決するために使用されます.1つのgoroutineブロック待ちn個のgoroutineにも使用できますし、n個のgoroutineブロック待ち1個にも使用できます.またはn個のブロックがm個を待つ.

下層構造


下位構造には12バイト4バイトのカウンタが格納され、4バイトの待機者数、4バイトが信号量

方法


waitgroup構造には、Add,Wait,Doneの3つの方法があり、DoneがAdd(-1)を呼び出します.

方法の実現原理


Addメソッドでは,入力パラメータに基づいてカウンタを計算し,カウンタが0の場合,待機者個数に基づいてnと仮定すると,n回の解放信号量を呼び出して待機するgoroutineを起動する.
Waitメソッドでは,まずカウンタが0であると判断するとすぐに戻るのを待たず,そうでなければ待機者数を加算して信号量を用いて現在のgoroutineを保留し,使用方法も比較的簡単である.

waitgroupの使用


使い方も簡単です.仕事の携程がオンになるたびにAdd(1)、実行が終了するとDoneブロックが待機している携程はWait()を呼び出すだけでよい.

注意事項


1.waitgroup変数は、転送中に値タイプであるため、転送プロセスには転送ポインタが必要です.そうしないと、転送は過去にコピーされ、ワークシート呼び出しDoneは待機中のシートを起動しません.永久的な閉塞をもたらす.2.addとwaitは必ず同じシートで操作しなければならない.さもないとaddがもう一つの携帯電話の中にいたら、waitの携帯電話はまだ別の携帯電話のaddを待っていないかもしれません.
 
 
 

三:context


Golang contextはGolangの同時制御技術であり、WaitGroupとの違いはcontextが派生したgoroutineを制御しやすいことである.contextは主に子孫goroutineにコンテキスト情報を伝達するために用いられ、キャンセル信号、タイムアウト時間、カットオフ時間、k-vなどが含まれる.contextにより、同じリクエストによって生成されたgoroutineを容易に制約管理することができ、タイムアウト、deadline、さらにはこのリクエストに関連するすべてのgoroutineをキャンセルすることができます.コンテキストは,要求と生存周期変数を伝達する標準的な方法となっている.ネットワークプログラミングでは、1つのネットワーク要求Requestを受信し、Requestを処理する場合、データと論理処理、すなわち1つの要求Requestを取得するために異なるGoroutineを開いて、複数のGoroutineで処理する必要がある場合があります.これらのGoroutineはRequestの情報を共有する必要がある場合があります.また、Requestがキャンセルまたはタイムアウトされた場合、このRequestから作成されたすべてのGoroutineも終了する必要があります.

Contextインタフェース

type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() 

Deadlineはシーンを使用し、サブgoroutinueはタイムアウト時間を返します.Goroutineはタイムアウト時間を取得した後、たとえばio操作の一部にタイムアウト時間を設定できます.Doneメソッドは、Contextがオフになったか否かを示す信号であり、Doneチャネルがオフになった後、ErrメソッドはContextがオフになった理由を示すチャネル(channel)を返す.ValueはGoroutineにいくつかのデータを共有させることができます.もちろん、データを得るのは安全です.しかし、これらのデータを使用するときは、同期に注意してください.例えば、mapが返され、このmapの読み書きはロックされます.

Contextインタフェースの実装構造


emptycontextインプリメンテーションは、通常、親のcontext cancelCtxインプリメンテーションとして使用され、親goroutineがcancel関数をアクティブに呼び出して子goroutine timerCtxをキャンセルし、親goroutineがアクティブにキャンセルするか、cancel関数をタイミングまたは指定時間に呼び出して子goroutine valueCtxをキャンセルし、親goroutineが子goroutineに値を渡す

対外関数

//go  context 6 
func Background() Context
func TODO() Context
//   emptyCtx

func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
//  cancelCtx

func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
WithTimeout WithDeadline
//  timerCtx

func WithValue(parent Context, key, val interface{}) Context
//  valueCtx

使用方法


Goroutine、彼らの作成と呼び出しの関係はいつも階層的な呼び出しのように行われています.人の世代のように、より上部のGoroutineは、部下のGoroutineの実行を自発的に閉じる方法があります(そうしないと、プログラムが暴走する可能性があります).このような関係を実現するために、Context構造も木のように、葉ノードは常にルートノードから派生しなければならない.
Contextツリーを作成するには、ルートノード、contextを取得します.Background関数の戻り値はルートノードBackground()であり,Requestを処理する最上位contextとしてしばしば存在する.ルートノードがあれば、他のサブノード、孫ノードをどのように作成すればいいのでしょうか.contextパッケージは、次のような複数の関数を作成します.

使用仕様


1.contextを構造体に格納のではなく、明示的に伝達する.contextを最初のパラメータとし、一般的に変数をctx 3と命名する.プログラムが許可しても、nilのcontextは渡さないで、contextを使うかどうか分からない場合はcontextを使います.TODO()に代わって4.context.WithValue()は、要求範囲の値のみを渡すために使用され、オプションパラメータ5は渡さない.複数の異なるgoroutineで使用されていてもcontextは安全です

使用例


valueCtxここでサブキャリアではctxの値処理ロジックが使用されているか、キャンセル終了の実行を待つか、ここでは終了しません.valueCtxにはキャンセル関数がなく、一般的には他の組み合わせで使用されています.
package main

import (
	"fmt"
	"time"
	"context"
)

func HandelRequest(ctx context.Context) {
	for {
		select {	
			case