---
# System prepended metadata

title: 2020 年 11 月

---

2020 年 11 月
===

# 蒼時

## Parallelism（並行） 和 Concurrency（並發）

要討論 Thread 的第一件事情就是先把「並行」跟「並發」區分出來。

Parallelism 是指「同時」的處理，也就是在多個 CPU 上同時處理任務。而 Concurrency 則是「交替」的處理，雖然從結果上來看可能都是把事情做完，但並發實際上並非真正的同時處理，只是因為處理速度足夠快而讓人感覺是「同時」進行的。

可以參考[這篇文章](https://medium.com/mr-efacani-teatime/concurrency%E8%88%87parallelism%E7%9A%84%E4%B8%8D%E5%90%8C%E4%B9%8B%E8%99%95-1b212a020e30)的插圖

## Race Condition（競爭條件）

當程式同時處理的時候，就可能會因為同時對某一個數值「寫入」造成預期外的結果。

舉例來說，假設我們進行一個 `a++` 的處理，現在同時有兩個 Thread 在執行

初始狀態：`a = 1`
Thread 1：`a++` => `a = 1` => `a = a + 1` => `a = 2`
Thread 2：`a++` => `a = 1` => `a = a + 1` => `a = 2`

此時我們原本預期 `a = 3` 但實際上因為 Thread 1 和 Thread 2 都讀取到的是 `a = 1` 因此最後結果都會變成 `a = 2` 而不是我們預期的 `a = 3`

> 其實這跟在處理資料庫的 Phantom Read（幻讀）情境是類似的，另外即使是 Concurrency 也是會發生 Race Condition 的

## Mutex（互斥鎖）

透過 Mutex 就可以避免 Race Condition 的發生，這是因為當我們使用 Mutex 之後就會限制能夠存取的 Thread 同時間只能有一個，進而堵塞其他 Thread 運行。

以 Ruby 為例子，會像這樣

```ruby
lock = Mutex.new

# Thread 1
Thread.new do
  lock.synchronize do
    sleep 1
    puts 'Thread#1'
  end
end

# Thread 2
Thread.new do
  lock.synchronize do
    sleep 1
    puts 'Thread#2'
  end
end

# ...
```

正常狀況下我們會看到 `Thread#1` 和 `Thread#2` 同時在畫面上被顯示出來，但是如果我們加上了 Mutex 之後，就需要等待 `Thread#1` 或者 `Thread#2` 先印出來後，再等待一秒才會印出另一個人。

這就表示 Mutex 限制了通時間只能有一個人進行處理，進而避免在同一個瞬間將變數寫入的情況。

## GIL/GVL（Global VM Lock）

Ruby 為了確保多執行緒（Multi-Thread）的穩定性因此以 Thread 為基礎加入了 Mutex 來處理，這就是 GVL 的設計，也因為這一層設計造成我們在 Ruby 運行時無法用最高效的方式運行。

> CRuby 使用的 Thread Library 叫做 `pthread` 是能夠在多核心上運行 Thread 的套件，因此 Ruby 的 Thread 是能在多核心上運作的，只是因為 GVL 的關係無法確實善用。

```ruby
a = []

threads = Array.new(100_00).map.with_index do |_, i|
  Thread.new do
    a << i
  end
end

sleep 0 until threads.map(&:stop?).reduce(:&)

puts a.size
```

像是上面這樣共用一個 `a` 變數的時候，就會自動觸發 GVL 來確保每一個 Thread 不會同時的被執行。

> 如何驗證的方式目前還沒有結論還需要再做研究，關於 GVL 對運行速度的影響可以參考[這篇文章](https://www.speedshop.co/2020/05/11/the-ruby-gvl-and-scaling.html)的說明

## Ractor

在 Ruby 3.0 預定增加的功能，不過 Ruby 2.7 就能夠使用到，實際上跟 Thread 類似但是做了一個不一樣的改變就是 GVL 的隔離。

簡單來說一個 Ractor 會有一個自己的 GVL 如此一來在操作的時候就不會因為互相搶佔 GVL 而出現效能上的問題，以往操作都會需要透過 Main Thread 上的 GVL 等待解鎖才能夠進行下一個操作，但是改由 Ractor 之後則會因為有各自的 GVL 而不會互相干擾，但相反的這樣的機制會讓我們無法在不同的 Ractor 之間共用變數。

# Cindy

Thread 為 CPU utilization 的最小單位，有自己的 program counter、stack、registers

Multi-threading vs Multi-processing

---

- [Thread](https://www.kshuang.xyz/doku.php/operating_system:course_concept:thread)
- [【恐龍】理解 Process & Thread](https://medium.com/erens-tech-book/%E7%90%86%E8%A7%A3-process-thread-94a40721b492)
- [[CS] 進程與線程的概念整理（process and thread）](https://pjchender.github.io/2020/09/20/cs-%E9%80%B2%E7%A8%8B%E8%88%87%E7%B7%9A%E7%A8%8B%E7%9A%84%E6%A6%82%E5%BF%B5%E6%95%B4%E7%90%86%EF%BC%88process-and-thread%EF%BC%89/)
- [Multiprocessing in Ruby - a Good Alternative to Threads?](https://naturaily.com/blog/multiprocessing-in-ruby)
- [多執行緒 (Multi-thread)](https://sls.weco.net/node/21324)
- [Threading and Code Execution in Rails](https://guides.rubyonrails.org/threading_and_code_execution.html#automatic-concurrency)
- [Tuning the application process and thread count
](https://www.phusionpassenger.com/library/config/nginx/optimization/#tuning-the-application-process-and-thread-count)
- [Web Server / Application Server / Rack / Process / Thread](https://mgleon08.github.io/blog/2016/10/23/web-server-application-server-rack-process-thread/)
- [分身之術(?) Thread](https://5xruby.tw/posts/what-is-thread/)
- [Program/Process/Thread 差異](https://medium.com/@totoroLiu/program-process-thread-%E5%B7%AE%E7%95%B0-4a360c7345e5)
- [Ruby on Rails 伺服器的選擇](https://blog.chh.tw/posts/ruby-on-rails-server-options/)
- [Deploy Rails App](https://sites.google.com/site/zhoubx/computer/ruby-on-rails/deploy-rails)
- [HTTP Server 大小事](https://old.michaelhsu.tw/2013/07/04/server/)
- [高效能 Web 伺服器開發](https://hackmd.io/@sysprog/fast-web-server?fbclid=IwAR2l0-EXiL3CWWgmfrybqM-6rWmGmp4zOKotbxEpsKT7JNu5MZnvrN7hcac)
