ディレクトリ
序文
- Benpianは上の注意「の実用的な言語を移動します。」
- Benpian大手レコードいくつかのメモ、またはどこgoplの異なるバージョンは言及しませんでした
- このセクションでは、すべての並行処理についてです、もっと重要なのは、それは多くの努力をしました
によって複雑
- パラレルが異なる上に同時に異なるコードセグメントを可能にすることで、物理プロセッサ(CPU)上で実行します
- パラレルは、同時に多くのことをやっています
- 同時実行は、これらの事はそれだけの半分が中断されたん何かを行うことができますたくさんのことを管理しています
スレッド(スレッド)とプロセス(過程)
- アプリケーションを実行する場合、オペレーティングシステムは、このためのプログラムを起動しますプロセス、このプロセスは、アプリケーションの様々な(メモリアドレス空間、ファイルやデバイスハンドル、などの運用・保守にリソースを使用する必要が含まスレッド、など)同等のコンテナ
- スレッドは、オペレーティング・システムは、スケジュールされた実行空間、ある関数で書かれたコードを実行する(これは、OSのスレッドスケジューラ、判別ゴルーチンスケジューラです)
- 各プロセスは少なくとも一つを含む糸を、各プロセスの初期スレッドが呼び出されるメインスレッド
- 以来、メインスレッドのスペースがあるアプリケーションスペース自体のため、メインスレッドの終了、アプリケーションが終了します
- OSスレッドスケジューラにスレッドをスケジュールすることができ、プロセッサ(CPU)ランニング
- オペレーティング・システムの物理プロセッサ(CPU)のスケジューラ・スレッドとスレッドの実行
ゴルーチンの概要
- CSP(一連の処理を通信)パラダイム(枠組み)と呼ばれる同時同期モデルから言語を行きます
- 実行するために他の関数の機能を独立させるための能力を指す同時言語を行きます
- あなたは、関数ゴルーチンを作成すると、Goが仕事の独立したユニットとして扱います
- このユニットは、(によってスケジュールされたゴルーチンスケジューラ使用可能に実装された)論理プロセッサの実行します
- ゴルーチンスケジューラが作成され、実行時間が割り当てられ、すべてのゴルーチンを管理することができ、オペレーティング・システムは、することができ、スレッド言語ランタイムとの論理プロセッサ結合、および論理プロセッサゴルーチン上で実行されています
ゴルーチン並行性と並列性
- で、オペレーティングシステムの物理プロセッサのスケジューリングスレッドのGo言語のプログラムが実行されている間、実行するために、論理プロセッサ上のスケジューリングゴルーチンの実行
- 各論理プロセッサ毎にバインドされている単一のOSスレッド
- バージョン1.5では、移動は、各利用可能な言語ランタイムのためであろう物理プロセッサ(CPU)が割り当てられる論理プロセッサ前バージョン1.5、アプリケーション全体が一つだけ割り当て、デフォルトで、論理プロセッサを
- あなたはゴルーチンと実行する準備ができてを作成した場合、これはゴルーチン配置されます囲碁スケジューラのグローバル実行キューをその後、囲碁スケジューラこのゴルーチンが論理プロセッサに割り当てられますが、論理プロセッサが対応して配置されるローカルのオペレーティングキュー
- ローカル実行キューゴルーチンが割り当てられて知って待たなければならない論理プロセッサの実行を
- 論理プロセッサは一意のオペレーティングシステムに接続されているスレッド
- あなたはゴルーチンの実行中、ブロッキングシステムコールを実行する必要がある場合、スレッドをしてからゴルーチンます論理プロセッサの分離、スレッドは、呼び出しを返すためにシステムを待ち、目詰まりしていきます
- 同時に、論理プロセッサが実行するスレッドを失い、その後、ゴースケジューラは、新しい作成したスレッドを、そしてスレッドがにバインドされている論理プロセッサ
- 之后,Go调度器会从本地运行队列里选择另一个goroutine来运行
一旦被阻塞的系统调用返回,对应的goroutine会被放到本地运行队列,而之前的线程会保存好,以便后用
- Go调度器对可以创建的逻辑处理器的数量没有限制,但Go语言运行时默认限制每个程序最多创建10000个线程
- 可以通过runtime/debug包的SetMaxThreads方法来更改每个程序最多创建的线程数
- 如果希望goroutine并行,必须使用多于一个逻辑处理器。
- 当有多个逻辑处理器时,Go调度器会将goroutine平等分配到每个逻辑处理器上,也就是让goroutine在不同的线程上运行
不过要想真的实现并行的效果,用户需要让自己的程序运行在多个物理处理器(CPU)的机器上
概念小整理
- 上述有关并发的概念都加粗处理了
- 物理处理器,线程,进程,主线程,应用程序,操作系统线程调度器,Go调度器,逻辑处理器,全局运行队列,本地运行队列
- 笔者的小结:
1.当启动一个应用程序,操作系统会为其创建相应的进程,
2.进程拥有应用程序所需的各种资源,包括内存地址空间,线程等
3.每个进程至少有一个线程,每个进程的初始线程被称为主线程
4.线程是一个执行空间,而主线程的空间就是应用程序的空间,因此主线程终止,应用程序也会终止
5.操作系统线程调度器可以将线程调度到物理处理器(CPU)
6.物理处理器(CPU)调度线程并运行
7.对于Go语言1.5以上版本的程序(进程)而言,Go调度器默认会为每个可用物理处理器(CPU),分配一个逻辑处理器
8.创建一个goroutine并运行,这个goroutine会被放在Go调度器的全局运行队列
9.Go调度器负责把这些队列中goroutine分配给一个逻辑处理器,并且将这个逻辑处理器绑定到唯一的操作系统线程
10.逻辑处理器会将相应的goroutine放入本地运行队列
11.本地运行队列中的goroutine会一直等待直到自己被分配到逻辑处理器执行
12.当goroutine执行一个阻塞的系统调用,其对应线程会从逻辑处理器上分离,该线程被阻塞,等待系统调用的返回
13.Go调度器会为失去线程的逻辑处理器创建一个新线程,并将新线程绑定到该逻辑处理器上
14.系统调用执行完成并返回,对应的goroutine会放回到本地运行队列,而之前的线程会被保存后,以便后用
goroutine
- runtim包中的GOMAXPROCS(num)函数可以设置分配给Go调度器使用的逻辑处理器的数量
- runtime包中的NumCPU()可以获取可以使用的物理处理器数量
- sync包中WaitGroup类型,通过它的add方法可以计数,Done方法来减少计数,Wait方法来等待计数结束
竞争状态(race condition)
- 定义:如果两个或多个goroutine在没有相互同步的情况下,访问某个共享的资源,并试图同时读和写这个资源,就处于相互竞争的状态
- Go语言有一个工具可以在代码里检测竞争状态:go build -race
- gopl-zh的翻译者翻译成了竞争条件,反而不好理解
锁住共享资源(竞争状态的处理方法)
- sync/atomic包中原子函数
- sync包中的互斥锁(gopl还提到了读写锁)
- 通道方法:
无缓冲通道
有缓存通道
特别说明:当通道关闭后,goroutine依旧可以从通道接收数据,但是不能再向通道里发送数据
并发模式
runner
- runner包用于展示如何使用通道来监视程序的执行时间,如果程序运行时间太长,也可以用runner包来终止运行
- 笔者理解:使用Runner模式来执行一系列串行任务,可以设置运行的时间,还可以终止运行
- corn作业 :crontab命令常见于Unix和类Unix的操作系统之中,用于设置周期性被执行的指令。该命令从标准输入设备读取指令,并将其存放于“crontab”文件中,以供之后读取和执行。该词来源于希腊语chronos(χρόνος),原意是时间。通常,crontab储存的指令被守护进程激活,crond常常在后台运行,每一分钟检查是否有预定的作业需要执行。这类作业一般称为cron jobs。
pool
- pool包用于展示如何使用有缓冲的通道实现资源池,来管理可以在任意数量的goroutine之间共享及独立使用的资源
- Go1.5版本并没有pool包,而1.6及以后版本中,实现标准库sync.Pool资源池,推荐使用
work
- work包的目的是展示如何使用无缓冲的通道来创建一个goroutine池,这些goroutine执行并控制一组工作,让其并发执行
小结
- 可以使用通道来控制程序的生命周期
- 带default分之的select语句可以用来尝试向通道发送或者接收数据,而不会阻塞
- 有缓冲的通道可以用来管理一组可复用的资源
- 语言运行时会处理好通道的协作和同步
- 使用无缓冲的通道来创建完成工作的goroutine池
- 任何时间都可以用无缓冲的通道来让两个goroutine交换数据,在通道操作完成时一定保证对方接收到数据