Thông dịch viên Ruby sử dụng một quy trình duy nhất theo thiết kế. Điều này có nghĩa là trên cpu 8 lõi hiện đại của bạn, tập lệnh của bạn sẽ chỉ sử dụng tối đa 1/8 sức mạnh xử lý của bạn. Trong bài viết này, chúng ta sẽ thấy nhiều hơn về ruby đa luồng và đa quy trình.
Sử dụng nhiều chủ đề
Trình thông dịch ruby Matz sử dụng GIL (Khóa phiên dịch toàn cầu), do đó nó chỉ cho phép một luồng chạy cùng một lúc. Vì vậy, trong các tác vụ ràng buộc cpu, không có lợi ích gì khi sử dụng đa luồng và nó sẽ không mang lại lợi ích gì cho bạn (trong ruby). Đầu tiên, chúng ta hãy lấy ví dụ này để tính số Fibonacci. Đó hoàn toàn là một nhiệm vụ ràng buộc cpu.
1 2 3 4 5 | <span class="token keyword">def</span> <span class="token function">fib</span> <span class="token punctuation">(</span> n <span class="token punctuation">)</span> <span class="token keyword">return</span> n <span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token number">0</span> <span class="token punctuation">,</span> <span class="token number">1</span> <span class="token punctuation">]</span> <span class="token punctuation">.</span> include <span class="token operator">?</span> <span class="token punctuation">(</span> n <span class="token punctuation">)</span> <span class="token function">fib</span> <span class="token punctuation">(</span> n <span class="token operator">-</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token function">fib</span> <span class="token punctuation">(</span> n <span class="token operator">-</span> <span class="token number">2</span> <span class="token punctuation">)</span> <span class="token keyword">end</span> |
1 2 | <span class="token constant">Benchmark</span> <span class="token punctuation">.</span> measure <span class="token punctuation">{</span> <span class="token number">10.</span> times <span class="token punctuation">{</span> <span class="token function">fib</span> <span class="token punctuation">(</span> <span class="token number">35</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
1 2 3 4 5 6 7 | (CPU time|system CPU time|user and system CPU times|real time) 38.243695 0.647830 38.891525 ( 41.074481) 36.667084 0.550266 37.217350 ( 38.464907) 38.844508 0.711785 39.556293 ( 42.610056) =>AVG: 40.72s |
Bây giờ hãy chạy nó bằng 10 luồng.
1 2 3 4 5 6 7 8 | <span class="token constant">Benchmark</span> <span class="token punctuation">.</span> measure <span class="token keyword">do</span> threads <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token number">10.</span> times <span class="token keyword">do</span> threads <span class="token operator"><</span> <span class="token operator"><</span> <span class="token builtin">Thread</span> <span class="token punctuation">.</span> <span class="token keyword">new</span> <span class="token punctuation">{</span> <span class="token builtin">Thread</span> <span class="token punctuation">.</span> current <span class="token punctuation">[</span> <span class="token symbol">:output</span> <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">fib</span> <span class="token punctuation">(</span> <span class="token number">35</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">end</span> threads <span class="token punctuation">.</span> <span class="token keyword">each</span> <span class="token punctuation">{</span> <span class="token operator">|</span> thread <span class="token operator">|</span> thread <span class="token punctuation">.</span> join <span class="token punctuation">}</span> <span class="token keyword">end</span> |
Trên một thế giới lý tưởng, chúng tôi hy vọng sẽ tăng gấp 10 lần hiệu suất. Nhưng,
1 2 3 4 5 6 | 38.623686 0.611559 39.235245 ( 40.751415) 38.077194 0.579472 38.656666 ( 39.956344) 38.445872 0.603536 39.049408 ( 40.273643) =>AVG: 40.33s |
Vì vậy, lợi ích của việc sử dụng chủ đề là gì? Câu trả lời là, Không (nếu bạn đang cố gắng giải quyết vấn đề ràng buộc cpu). Nhưng, nếu bạn đang cố gắng giải quyết vấn đề bị ràng buộc IO, thì các luồng sẽ tăng tốc hiệu suất của bạn lên rất nhiều.
Ví dụ: Thực hiện các yêu cầu HTTP với nhiều luồng
Hãy tưởng tượng một kịch bản, trong đó chúng ta có một phương pháp kiểm tra xem nó có thể truy cập vào một số trang web và phản hồi lại bằng mã trạng thái HTTP hay không.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token keyword">require</span> <span class="token string">'benchmark'</span> <span class="token keyword">require</span> <span class="token string">'net/http'</span> <span class="token keyword">def</span> check servers servers <span class="token punctuation">.</span> <span class="token keyword">each</span> <span class="token keyword">do</span> <span class="token operator">|</span> server <span class="token operator">|</span> response <span class="token operator">=</span> <span class="token constant">Net</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token constant">HTTP</span> <span class="token punctuation">.</span> <span class="token function">get_response</span> <span class="token punctuation">(</span> server <span class="token punctuation">,</span> <span class="token string">'/'</span> <span class="token punctuation">)</span> puts server <span class="token punctuation">,</span> response <span class="token punctuation">.</span> code <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token constant">SERVERS</span> <span class="token operator">=</span> <span class="token builtin">Array</span> <span class="token punctuation">.</span> <span class="token keyword">new</span> <span class="token punctuation">(</span> <span class="token number">100</span> <span class="token punctuation">,</span> <span class="token string">"www.google.com"</span> <span class="token punctuation">)</span> puts <span class="token constant">Benchmark</span> <span class="token punctuation">.</span> measure <span class="token punctuation">{</span> <span class="token function">check</span> <span class="token punctuation">(</span> <span class="token constant">SERVERS</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
1 2 3 | ruby thread.rb 0.078843 0.046223 0.125066 ( 27.263542) |
Bây giờ, hãy viết lại mã để sử dụng nhiều luồng để thực hiện công việc
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token keyword">def</span> check servers threads <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> servers <span class="token punctuation">.</span> <span class="token keyword">each</span> <span class="token keyword">do</span> <span class="token operator">|</span> server <span class="token operator">|</span> threads <span class="token operator"><</span> <span class="token operator"><</span> <span class="token builtin">Thread</span> <span class="token punctuation">.</span> <span class="token keyword">new</span> <span class="token punctuation">{</span> response <span class="token operator">=</span> <span class="token constant">Net</span> <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token constant">HTTP</span> <span class="token punctuation">.</span> <span class="token function">get_response</span> <span class="token punctuation">(</span> server <span class="token punctuation">,</span> <span class="token string">'/'</span> <span class="token punctuation">)</span> puts server <span class="token punctuation">,</span> response <span class="token punctuation">.</span> code <span class="token punctuation">}</span> <span class="token keyword">end</span> threads <span class="token punctuation">.</span> <span class="token keyword">each</span> <span class="token punctuation">{</span> <span class="token operator">|</span> thread <span class="token operator">|</span> thread <span class="token punctuation">.</span> join <span class="token punctuation">}</span> <span class="token keyword">end</span> |
1 2 | 0.094302 0.038597 0.132899 ( 1.383422) |
Đó là một cải tiến lớn so với việc thực hiện luồng đơn của chúng tôi. Về mặt tích cực, việc chạy nhiều luồng không làm tăng mức độ sử dụng bộ nhớ như sử dụng đa tiến trình.
Những lợi ích
- Tăng tốc cho các hoạt động chặn
- Các biến có thể được chia sẻ / sửa đổi (beaware của deadlocks)
- Không sử dụng thêm bộ nhớ
Nhược điểm
- Khó gỡ lỗi hơn nhiều
Sử dụng nhiều quy trình
Hãy nhớ việc triển khai Wikipedia của chúng tôi từ phần #threads.
1 2 3 4 5 | <span class="token keyword">def</span> <span class="token function">fib</span> <span class="token punctuation">(</span> n <span class="token punctuation">)</span> <span class="token keyword">return</span> n <span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token number">0</span> <span class="token punctuation">,</span> <span class="token number">1</span> <span class="token punctuation">]</span> <span class="token punctuation">.</span> include <span class="token operator">?</span> <span class="token punctuation">(</span> n <span class="token punctuation">)</span> <span class="token function">fib</span> <span class="token punctuation">(</span> n <span class="token operator">-</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token function">fib</span> <span class="token punctuation">(</span> n <span class="token operator">-</span> <span class="token number">2</span> <span class="token punctuation">)</span> <span class="token keyword">end</span> |
1 2 | <span class="token constant">Benchmark</span> <span class="token punctuation">.</span> measure <span class="token punctuation">{</span> <span class="token number">10.</span> times <span class="token punctuation">{</span> <span class="token function">fib</span> <span class="token punctuation">(</span> <span class="token number">35</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
1 2 3 4 5 6 7 | (CPU time|system CPU time|user and system CPU times|real time) 38.243695 0.647830 38.891525 ( 41.074481) 36.667084 0.550266 37.217350 ( 38.464907) 38.844508 0.711785 39.556293 ( 42.610056) =>AVG: 40.72s |
Bây giờ chúng ta sẽ thử chạy nó với nhiều tiến trình thay vì các luồng. Hàm viết lại sẽ là
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token constant">Benchmark</span> <span class="token punctuation">.</span> measure <span class="token punctuation">{</span> read_stream <span class="token punctuation">,</span> write_stream <span class="token operator">=</span> <span class="token builtin">IO</span> <span class="token punctuation">.</span> pipe <span class="token number">10.</span> times <span class="token keyword">do</span> <span class="token constant">Process</span> <span class="token punctuation">.</span> fork <span class="token keyword">do</span> write_stream <span class="token punctuation">.</span> puts <span class="token function">fib</span> <span class="token punctuation">(</span> <span class="token number">35</span> <span class="token punctuation">)</span> <span class="token keyword">end</span> <span class="token keyword">end</span> <span class="token constant">Process</span> <span class="token punctuation">.</span> waitall write_stream <span class="token punctuation">.</span> close results <span class="token operator">=</span> read_stream <span class="token punctuation">.</span> read read_stream <span class="token punctuation">.</span> close <span class="token punctuation">}</span> |
Bây giờ, hãy xem điểm chuẩn.
1 2 3 4 5 6 | 0.001240 0.005190 63.827237 ( 17.158324) 0.001579 0.007635 65.032995 ( 19.821757) 0.001433 0.006900 64.022068 ( 18.152649) =>AVG: 18.38s |
Vì vậy, so với 40 giây, nó sử dụng 18 giây. Đó là một cải tiến tuyệt vời. Lưu ý sử dụng bộ nhớ
Việc thực hiện này đang sử dụng bộ nhớ cao hơn 10 lần. Đó là sự đánh đổi.
Những lợi ích
- Tăng tốc thông qua nhiều CPU
- Tăng tốc cho các hoạt động chặn
- Các biến được bảo vệ khỏi sự thay đổi
- Các tiến trình con bị giết khi tiến trình chính của bạn bị giết thông qua Ctrl + c hoặc giết -2
Nhược điểm
- Sử dụng bộ nhớ sẽ cao hơn.
Tóm lược
Nó được mô tả tốt nhất trong bài viết tuyệt vời này từ Eqbal Qur'an .
Để kết luận, chúng ta có thể nói, không có kết thúc nào là giải pháp tốt nhất. Chúng tôi phải hiểu khối lượng công việc và chọn giải pháp tốt nhất cho vấn đề của chúng tôi.
Những điều cần học
Ruby không đồng bộ -by Samuel Williams
GIL – Khóa phiên dịch toàn cầu