Computer >> Máy Tính >  >> Lập trình >> Ruby

Làm chủ Đồng tiền

Làm chủ đồng thời

Nhiều người sẽ sử dụng ứng dụng của bạn cùng một lúc và bạn muốn phân phối ứng dụng của mình nhanh nhất có thể. Vì vậy, bạn sẽ cần một số cách để xử lý đồng thời. Đừng sợ! Hầu hết các máy chủ web đã làm điều này theo mặc định. Nhưng khi bạn cần mở rộng quy mô, bạn muốn sử dụng đồng thời theo cách hiệu quả nhất có thể.

Các loại đồng thời khác nhau

Có nhiều cách để xử lý đồng thời:đa quy trình, đa luồng và theo hướng sự kiện. Mỗi loại đều có công dụng, ưu và nhược điểm của chúng. Trong bài viết này, bạn sẽ tìm hiểu chúng khác nhau như thế nào và khi nào thì sử dụng.

Đa quy trình (Unicorn)

Đây là cách dễ nhất để xử lý đồng thời. Một quy trình tổng thể tự phân nhánh cho nhiều quy trình công nhân. Quy trình worker xử lý các yêu cầu thực tế, trong khi master quản lý các worker.

Mỗi quy trình công nhân có đầy đủ cơ sở mã trong bộ nhớ. Điều này làm cho phương pháp này khá tốn bộ nhớ và khó mở rộng quy mô đến các cơ sở hạ tầng lớn hơn.

Tóm tắt nhiều quy trình
Trường hợp sử dụng Một ví dụ không phải ruby ​​mà bạn có thể biết là trình duyệt Chrome. Nó sử dụng đồng thời nhiều quy trình để cung cấp cho mỗi tab quy trình riêng của chúng. Nó cho phép một tab duy nhất bị sập mà không cần gỡ toàn bộ ứng dụng xuống. Trong trường hợp của họ, nó cũng giúp tách biệt các phần khai thác thành một tab.
Ưu điểm Thực hiện đơn giản nhất.
Bỏ qua những khó khăn về an toàn luồng.
Mỗi nhân viên có thể gặp sự cố mà không làm hỏng phần còn lại của hệ thống.
Nhược điểm Mỗi quá trình sẽ tải toàn bộ codebase vào bộ nhớ. Điều này làm cho nó sử dụng nhiều bộ nhớ.
Do đó, nó không mở rộng đến số lượng lớn các kết nối đồng thời.

Đa luồng (Puma)

Mô hình phân luồng này cho phép một quá trình xử lý nhiều yêu cầu cùng một lúc. Nó làm như vậy bằng cách chạy nhiều chuỗi trong một quy trình.

Trái ngược với cách tiếp cận đa quy trình, tất cả các luồng chạy trong cùng một quy trình. Điều này có nghĩa là chúng chia sẻ dữ liệu chẳng hạn như các biến toàn cục. Do đó, chỉ những phần nhỏ bộ nhớ bổ sung được sử dụng cho mỗi luồng.

Khóa thông dịch viên toàn cầu

Điều này đưa chúng ta đến khóa thông dịch viên toàn cầu (GIL) trong MRI. GIL là một khóa xung quanh việc thực thi tất cả mã Ruby. Mặc dù các chuỗi của chúng tôi dường như chạy song song, chỉ một chuỗi hoạt động tại một thời điểm.

IO hoạt động bên ngoài GIL. Khi bạn thực hiện một truy vấn cơ sở dữ liệu chờ kết quả trả về, nó sẽ không khóa. Một chủ đề khác sẽ có cơ hội thực hiện một số công việc trong thời gian chờ đợi. Nếu bạn thực hiện nhiều phép toán và phép toán trên các hàm băm hoặc mảng trong chuỗi, bạn sẽ chỉ sử dụng một lõi duy nhất nếu bạn sử dụng MRI. Trong hầu hết các trường hợp, bạn vẫn cần nhiều quy trình để sử dụng đầy đủ máy của mình. Hoặc bạn có thể sử dụng Rubinius hoặc jRuby, không có GIL.

An toàn chuỗi

Nếu bạn sử dụng nhiều luồng, bạn phải cẩn thận viết tất cả mã điều khiển dữ liệu được chia sẻ theo cách an toàn cho luồng. Bạn có thể làm điều này chẳng hạn bằng cách sử dụng Mutex để khóa các cấu trúc dữ liệu được chia sẻ trước khi bạn thao tác chúng. Điều này sẽ đảm bảo rằng các chuỗi khác không dựa trên công việc của họ trên dữ liệu cũ trong khi bạn đang thay đổi dữ liệu.

Tóm tắt đa luồng
Trường hợp sử dụng Đây là tùy chọn "giữa đường". Được sử dụng cho nhiều ứng dụng web tiêu chuẩn cần xử lý vô số yêu cầu ngắn (chẳng hạn như ứng dụng web bận).
Ưu điểm Sử dụng ít bộ nhớ hơn so với đa quy trình.
Nhược điểm Bạn phải đảm bảo mã của mình an toàn cho chuỗi.
Nếu một chuỗi gây ra sự cố, nó có thể làm hỏng quy trình của bạn.
GIL khóa tất cả các hoạt động ngoại trừ I / O.

Vòng lặp sự kiện (Mỏng)

Vòng lặp sự kiện được sử dụng khi bạn cần thực hiện nhiều thao tác I / O đồng thời. Bản thân mô hình này không buộc thực hiện nhiều yêu cầu cùng một lúc, nhưng đây là một cách hiệu quả để xử lý nhiều người dùng đồng thời.

Dưới đây, bạn sẽ thấy một vòng lặp sự kiện rất đơn giản được viết bằng Ruby. Vòng lặp sẽ lấy sự kiện từ event_queue và xử lý nó. Nếu không có sự kiện nào, nó sẽ ngủ và lặp lại để xem có sự kiện mới trong hàng đợi hay không.

Vòng lặp
loop do
  if event_queue.any?
    handle_event(event_queue.pop)
  else
    sleep 0.1
  end
end

Phiên bản minh họa

Trong hình minh họa này, chúng tôi đang tiến thêm một bước nữa. Vòng lặp sự kiện giờ đây thực hiện một bước nhảy đẹp mắt với hệ điều hành, hàng đợi và một số bộ nhớ.

Từng bước

  1. Hệ điều hành theo dõi tình trạng sẵn có của mạng và ổ đĩa.
  2. Khi hệ điều hành thấy I / O đã sẵn sàng, hệ điều hành sẽ gửi một sự kiện đến hàng đợi.
  3. Hàng đợi là danh sách các sự kiện mà từ đó vòng lặp sự kiện chiếm vị trí hàng đầu.
  4. Vòng lặp sự kiện xử lý sự kiện.
  5. Nó sử dụng một số bộ nhớ để lưu trữ dữ liệu meta về các kết nối.
  6. Nó có thể gửi lại một sự kiện mới trực tiếp vào hàng đợi sự kiện. Ví dụ:thông báo đóng hàng đợi dựa trên nội dung của một sự kiện.
  7. Nếu nó muốn thực hiện một thao tác I / O, nó sẽ cho HĐH biết rằng nó quan tâm đến một hoạt động I / O cụ thể. Hệ điều hành theo dõi mạng và đĩa (xem [1]) và thêm lại sự kiện khi I / O sẵn sàng.
Tóm tắt vòng lặp sự kiện
Trường hợp sử dụng Khi sử dụng nhiều kết nối đồng thời cho người dùng của bạn. Hãy nghĩ đến các dịch vụ như Slack. Thông báo của Chrome.
Ưu điểm Hầu như không có chi phí bộ nhớ cho mỗi kết nối.
Quy mô cho một số lượng lớn các kết nối song song.
Nhược điểm Đây là một mô hình tinh thần khó hiểu.
Kích thước lô phải nhỏ và có thể dự đoán được để tránh xếp hàng.

Bạn nên sử dụng cái nào?

Chúng tôi hy vọng bài viết này đã giúp bạn hiểu rõ hơn về các mô hình đồng thời khác nhau. Đó là một số vấn đề khó nắm bắt hơn với tư cách là nhà phát triển, nhưng hiểu được nó sẽ cung cấp cho bạn công cụ để thử nghiệm và sử dụng thiết lập phù hợp cho ứng dụng của bạn.

Tóm lại

  • Đối với hầu hết các chuỗi ứng dụng đều có ý nghĩa, hệ sinh thái Ruby / Rails dường như (dần dần) đang chuyển động theo hướng này.
  • Nếu bạn chạy các ứng dụng đồng thời cao với các luồng chạy dài, vòng lặp sự kiện cho phép bạn mở rộng quy mô.
  • Nếu bạn không có một trang web có lưu lượng truy cập cao hoặc bạn mong muốn nhân viên của mình sẽ ngừng sử dụng nhiều quy trình cũ tốt.

Và, có thể chạy một vòng lặp sự kiện, bên trong một chuỗi, bên trong một thiết lập nhiều quy trình. Vì vậy, có, bạn có thể có món bánh mì nướng của mình và ăn nó luôn!

Nếu bạn muốn đọc thêm về các mô hình đồng thời này, hãy xem các bài viết chi tiết của chúng tôi về đa quy trình, đa luồng và vòng lặp sự kiện.