一方通行チャネルアプリケーション「生産的な消費者モデル」
最も典型的なアプリケーションは、一方向のチャネルである「生産者 - 消費者モデル。」
いわゆる「生産者 - 消費者モデル」(等関数)モジュールデータを生成するための責任を、他のモジュールによる処理のために責任がある(ここで、モジュールが広い、クラス、関数、コルーチン、スレッド、プロセスとすることができますなど)。消費者と呼ばれ、データ処理モジュールと、データ生成モジュールは、それが適切プロデューサーと呼ばれます。
アブストラクトのみ生産者と消費者が、プロデューサ/コンシューマモデルでも十分。また、このモードは仲介者として、生産者と消費者の間にバッファを持っている必要があります。バッファへのメーカデータは、データバッファと消費者から採取しました。図おおよその構造を次のように:
例として、あなたは普通の手紙を送りたい場合は、おおよそ次のように何を、理解を助けるために手紙を送ります:
書かれた手紙 - データはメーカーに対応
メールボックスへの手紙 - 同等のデータバッファメーカーに
ポストマンの手紙は、メールボックスから削除されました - データは、消費者に対応するフェッチバッファ
適切な治療を行うために郵便局に手紙を取るポストマン - 消費者データ処理の同等
だから、このバッファには何を使用ですか?なぜ過去に直接データを渡すために、消費者の生産者に直接関数を呼び出して、それのようなバッファ余分を設定していませんか?
バッファの利点は、おそらく、次のとおりです。
1:デカップリング
生産者と消費者が2つのクラスがあると仮定すると。あなたはプロデューサーが直接消費者のメソッドを呼び出してみましょう場合、消費者は生産者(すなわち、結合)に依存する必要があります。将来のコードの変更の消費者が生産者に直接影響を与える可能性がある場合。両者が結合の程度に直接依存しない両者のバッファに依存している場合に対応して減少されます。
メールボックスが(バッファ)を使用しない場合は、上記の例に続いて、手紙は郵便配達に直接適用する必要があります。その後、郵便配達が誰であるかを知っている必要があります。世代とあなたと郵便配達(生産者と消費者の強い結合に相当)との間のこの依存関係。一日郵便配達置換する場合は、(同等の変更は、消費者のプロデューサーコードの変更につながる)次の郵便配達を再認識する必要があります。比較的固定したメールボックスが、あなたはそれに依存して比較的低コスト(およびバッファ間の弱い結合に相当)です。
2:並行処理
消費者が直接メソッドを呼び出すプロデューサー、他の欠点があります。関数呼び出しが(またはブロッキング呼び出し)同期しているので、消費者の前に戻らない方法は、生産者はあそこに待っていました。場合に消費者データの処理は、生産者は時間の不当な廃棄物缶、遅いです。
プロデューサ/コンシューマモデルを使用した後、生産者と消費者は、2つの独立した同時被写体であってもよいです。バッファにメーカーのデータが失われた生産は、次のデータに行くことができます生産しました。基本的に、消費者の処理速度に依存しないでください。
実際には、ほとんどこの生産者 - 消費者モデルを持っていた、主に並行性の問題に対処するために使用されます。
例としては、ビューからの手紙を送ります。郵便配達員が手紙(ポーリングされ、消費者の同等)を送信する人、依頼するドアにドアを行っていた場合は、何のメールボックスが存在しない場合は、近くに郵便配達(閉塞プロデューサーに相当)を待っている交差点で愚かな地位を超える手紙を手に持っています。
3:キャッシュ
データのメーカの速度は、バッファのメリットが発揮される低速の場合。場合、高速製造データ、プロセスへの消費者の時間、未処理データを一時的にバッファに格納することができます。プロデューサー、消費者とのゆっくりに配置されたスローダウンスピードを製造します。
郵便配達だけで1000年の手紙を取ることができると仮定すると。送信するためにカードを挨拶特定のヒットバレンタインデーケースでは、我々は1000以上の文字、メールボックスこのバッファは便利になります。この時間を送信する必要があります。郵便配達は遅すぎるので、次の時間が引き継ぐ、ステージングでは、メールボックス内の文字を奪うように。
例えば:
package main
import "fmt"
// 此通道只能写,不能读。
func producer(out chan<- int) {
for i:= 0; i < 10; i++ {
out <- i*i // 将 i*i 结果写入到只写channel
}
close(out)
}
// 此通道只能读,不能写
func consumer(in <-chan int) {
for num := range in { // 从只读channel中获取数据
fmt.Println("num =", num)
}
}
func main() {
ch := make(chan int) // 创建一个双向channel
// 新建一个groutine, 模拟生产者,产生数据,写入 channel
go producer(ch) // channel传参, 传递的是引用。
// 主协程,模拟消费者,从channel读数据,打印到屏幕
consumer(ch) // 与 producer 传递的是同一个 channel
}
簡単な説明:最初に双方向チャネルを作成し、パラメータとして新しいゴルーチン、プロデューサメソッドに渡された双方向チャネルを開き、書き込み専用のチャンネルに変換されます。サブ生産で書き込み専用チャネルにデータを追加し、サイクルを開始コルーチン。メインコルーチン、読み取り専用の消費者であるチャネルの各サイクルからデータを読み出すことにより、双方向チャネルをチャネルになります消費者直接呼び出し方法。
注:パラメータとして渡されたチャネルである、参照によって渡されます。
ここでは、どのような順序処理シミュレートするために、消費者のモデルに応じて生成します。
電力会社のサイト、注文処理、非常に一般的な生産者 - 消費者モデルである:実際の開発では、生産者 - 消費者モデルのアプリケーションのような、非常に広範です。
多くのユーザーは、注文ボタン、バッファにすべてのデータの受注生産(キュー)をクリックして、消費者は、キューセンダデータウェアハウス管理システムから取り出されます。場合には
生産者 - 消費者モデルによって、注文システム、倉庫管理システムが隔離され、そしてユーザは、いつでも(生産データ)を注文することができます。オーダーシステムは、直接倉庫システムを呼び出す場合、ユーザーは、倉庫システムのリターンの結果まで待つ命令の下のボタンをクリックします。このような速度が非常に遅くなります。
注文の手順アナログ処理後。
package main
import "fmt"
type OrderInfo struct { // 创建结构体类型OrderInfo,只有一个id 成员
id int
}
func producer2(out chan <- OrderInfo) { // 生成订单——生产者
for i:=0; i<10; i++ { // 循环生成10份订单
order := OrderInfo{id: i+1}
out <- order // 写入channel
}
close(out) // 写完,关闭channel
}
func consumer2(in <- chan OrderInfo) { // 处理订单——消费者
for order := range in { // 从channel 取出订单
fmt.Println("订单id为:", order.id) // 模拟处理订单
}
}
func main() {
ch := make(chan OrderInfo) // 定义一个双向 channel, 指定数据类型为OrderInfo
go producer2(ch) // 建新协程,传只写channel
consumer2(ch) // 主协程,传只读channel
}
ORDERINFO注文情報として、ここでは簡単のために1つの属性のみの注文番号、そしてプロデューサーのシミュレーション10件の受注、顧客の注文が処理される農産物を定義します。