Suy nghĩ mở đầu
Làm thế nào bạn đi đến kết luận rằng một số phần của hệ thống sẽ có giá tốt hơn trong ngôn ngữ khác? Bạn đang gặp vấn đề về hiệu suất? Những vấn đề đó nghiêm trọng đến mức nào? Nếu nó có thể nhanh hơn, điều cần thiết là nó nhanh hơn?
Không đồng bộ một luồng
Có một số câu hỏi và các tài nguyên web khác đã giải quyết các khác biệt, ưu và nhược điểm của sự không đồng bộ đơn luồng so với đồng thời đa luồng. Thật thú vị khi đọc về cách mô hình không đồng bộ một luồng của Node.js thực hiện khi I / O là nút cổ chai lớn và có nhiều yêu cầu được phục vụ cùng một lúc.
Twisted, Tornado và các mô hình không đồng bộ khác sử dụng tuyệt vời của một luồng đơn. Vì rất nhiều chương trình web có rất nhiều I / O (mạng, cơ sở dữ liệu, v.v.), thời gian chờ đợi cho các cuộc gọi từ xa tăng lên đáng kể. Đó là thời gian có thể được dành để làm những việc khác, như khởi động các cuộc gọi cơ sở dữ liệu khác, kết xuất trang và tạo dữ liệu. Việc sử dụng chủ đề đơn đó là cực kỳ cao.
Một trong những lợi ích lớn nhất của sợi đơn không đồng pha là nó sử dụng nhiều ít bộ nhớ. Trong thực thi đa luồng, mỗi luồng yêu cầu một lượng bộ nhớ dự trữ nhất định. Khi số lượng chủ đề tăng lên, số lượng bộ nhớ cần thiết chỉ cho các chủ đề tồn tại. Vì bộ nhớ là hữu hạn, điều đó có nghĩa là có giới hạn về số lượng luồng có thể được tạo bất kỳ lúc nào.
Thí dụ
Trong trường hợp máy chủ web, giả vờ mỗi yêu cầu được cung cấp chủ đề rất riêng của nó. Cần có 1 MB bộ nhớ cho mỗi luồng và máy chủ web có 2GB RAM. Máy chủ web này sẽ có khả năng xử lý (khoảng) 2000 yêu cầu tại bất kỳ thời điểm nào trước khi không còn đủ bộ nhớ để xử lý nữa.
Nếu tải của bạn cao hơn đáng kể so với mức này, các yêu cầu sẽ mất một thời gian rất dài (khi chờ yêu cầu cũ hoàn thành) hoặc bạn sẽ phải ném thêm máy chủ vào cụm để mở rộng số lượng yêu cầu đồng thời có thể .
Đồng thời đa luồng
Thay vào đó, nhiều luồng đồng thời phụ thuộc vào việc thực thi một số tác vụ cùng một lúc. Điều đó có nghĩa là nếu một luồng bị chặn chờ cuộc gọi cơ sở dữ liệu để trả về, các yêu cầu khác có thể được xử lý cùng một lúc. Việc sử dụng luồng thấp hơn, nhưng số lượng luồng thực thi lớn hơn nhiều.
Mã đa luồng cũng khó hơn nhiều để lý do. Có vấn đề với khóa, đồng bộ hóa và các vấn đề tương tranh thú vị khác. Sự không đồng bộ đơn luồng không gặp phải vấn đề tương tự.
Tuy nhiên, mã đa luồng có hiệu năng cao hơn nhiều đối với các tác vụ chuyên sâu của CPU . Nếu không tồn tại cơ hội nào để tạo ra một luồng đối với năng suất, thì đó là một cuộc gọi mạng thường sẽ chặn một mô hình một chuỗi đơn giản, sẽ không có bất kỳ sự tương tranh nào.
Cả hai cùng tồn tại
Tất nhiên có sự chồng chéo giữa hai người; Họ không phải là loại trừ lẫn nhau. Ví dụ, mã đa luồng có thể được viết theo cách không chặn, để sử dụng tốt hơn từng luồng.
Điểm mấu chốt
Có nhiều vấn đề khác để xem xét, nhưng tôi thích nghĩ về hai vấn đề như thế này:
- Nếu chương trình của bạn bị ràng buộc I / O , thì tính không đồng bộ của một luồng có thể sẽ hoạt động khá tốt.
- Nếu chương trình của bạn bị ràng buộc CPU , thì một hệ thống đa luồng có thể sẽ là tốt nhất.
Trong trường hợp cụ thể của bạn, bạn cần xác định loại công việc không đồng bộ nào đang được hoàn thành và tần suất các nhiệm vụ đó phát sinh.
- Họ có xảy ra trên mọi yêu cầu? Nếu vậy, bộ nhớ có thể sẽ trở thành một vấn đề khi số lượng yêu cầu tăng lên.
- Là những nhiệm vụ được ra lệnh? Nếu vậy, bạn sẽ phải xem xét đồng bộ hóa nếu sử dụng nhiều luồng.
- Là những nhiệm vụ CPU chuyên sâu? Nếu vậy, một luồng đơn có thể theo kịp tải không?
Không có câu trả lời đơn giản. Bạn phải xem xét trường hợp sử dụng của bạn là gì, và thiết kế phù hợp. Đôi khi một mô hình đơn luồng không đồng bộ là tốt hơn. Những lần khác, sử dụng một số luồng để đạt được xử lý song song lớn là bắt buộc.
Những ý kiến khác
Có những vấn đề khác bạn cũng cần xem xét, thay vì chỉ mô hình tương tranh bạn chọn. Bạn có biết Erlang hoặc Clojure? Bạn có nghĩ rằng bạn có khả năng viết mã đa luồng an toàn bằng một trong những ngôn ngữ này để bạn cải thiện hiệu suất của ứng dụng của mình không? Sẽ mất nhiều thời gian để đạt được tốc độ trong một trong những ngôn ngữ này, và liệu ngôn ngữ bạn học có mang lại lợi ích cho bạn trong tương lai không?
Làm thế nào về những khó khăn liên quan đến giao tiếp giữa hai hệ thống này? Nó sẽ quá phức tạp để duy trì song song hai hệ thống riêng biệt? Hệ thống Erlang sẽ nhận các nhiệm vụ từ Django như thế nào? Erlang sẽ truyền đạt những kết quả đó trở lại Django như thế nào? Là hiệu suất đủ đáng kể một vấn đề mà sự phức tạp thêm vào là đáng giá?
Suy nghĩ cuối cùng
Tôi luôn thấy Django đủ nhanh và nó được sử dụng bởi một số trang web buôn bán rất nặng. Có một số tối ưu hóa hiệu suất bạn có thể thực hiện để tăng số lượng yêu cầu đồng thời và thời gian phản hồi. Phải thừa nhận rằng cho đến nay, tôi chưa làm gì với Celery, vì vậy việc tối ưu hóa hiệu suất thông thường có lẽ sẽ không giải quyết được bất kỳ vấn đề nào bạn có thể gặp phải với các tác vụ không đồng bộ này.
Tất nhiên, luôn có đề xuất ném thêm phần cứng vào vấn đề. Là chi phí cung cấp một máy chủ mới rẻ hơn chi phí phát triển và bảo trì của một hệ thống con hoàn toàn mới?
Tôi đã hỏi quá nhiều câu hỏi vào thời điểm này, nhưng đó là ý định của tôi. Câu trả lời sẽ không dễ dàng nếu không phân tích và biết thêm chi tiết. Có thể phân tích các vấn đề bắt nguồn từ việc biết các câu hỏi để hỏi, mặc dù vậy, rất hy vọng tôi đã giúp đỡ trên mặt trận đó.
Cảm giác ruột của tôi nói rằng viết lại bằng ngôn ngữ khác là không cần thiết. Sự phức tạp và chi phí có lẽ sẽ quá lớn.
Chỉnh sửa
Trả lời theo dõi
Theo dõi của bạn trình bày một số trường hợp sử dụng rất thú vị.
1. Django làm việc bên ngoài các yêu cầu HTTP
Ví dụ đầu tiên của bạn liên quan đến việc đọc thẻ NFC, sau đó truy vấn cơ sở dữ liệu. Tôi không nghĩ rằng việc viết phần này bằng ngôn ngữ khác sẽ hữu ích cho bạn, đơn giản vì việc truy vấn cơ sở dữ liệu hoặc máy chủ LDAP sẽ bị ràng buộc bởi I / O mạng (và có khả năng thực hiện cơ sở dữ liệu). Mặt khác, số lượng yêu cầu đồng thời sẽ bị ràng buộc bởi chính máy chủ, vì mỗi lệnh quản lý sẽ được chạy như một quy trình riêng của nó. Sẽ có thời gian thiết lập và phân tích ảnh hưởng đến hiệu suất, vì bạn không gửi tin nhắn đến một quy trình đã chạy. Tuy nhiên, bạn sẽ có thể gửi nhiều yêu cầu cùng một lúc, vì mỗi yêu cầu sẽ là một quy trình riêng biệt.
Trong trường hợp này, tôi thấy hai con đường bạn có thể điều tra:
- Đảm bảo rằng cơ sở dữ liệu của bạn có khả năng xử lý nhiều truy vấn cùng một lúc với nhóm kết nối. (Ví dụ, Oracle yêu cầu bạn định cấu hình Django phù hợp
'OPTIONS': {'threaded':True}
.) Có thể có các tùy chọn cấu hình tương tự ở cấp cơ sở dữ liệu hoặc cấp Django mà bạn có thể điều chỉnh cho cơ sở dữ liệu của riêng mình. Bất kể ngôn ngữ nào bạn viết các truy vấn cơ sở dữ liệu của mình, bạn sẽ phải đợi dữ liệu này trở lại trước khi bạn có thể bật đèn LED. Hiệu năng của mã truy vấn có thể tạo ra sự khác biệt và Django ORM không nhanh như chớp ( nhưng , thường đủ nhanh).
- Giảm thiểu thời gian thiết lập / phá hỏng. Có một quá trình liên tục chạy, và gửi tin nhắn đến nó. (Sửa lỗi cho tôi nếu tôi sai, nhưng đây là câu hỏi ban đầu của bạn thực sự tập trung vào.) Liệu quy trình này được viết bằng Python / Django hay ngôn ngữ / khung khác được trình bày ở trên. Tôi không thích ý tưởng sử dụng các lệnh quản lý thường xuyên như vậy. Có thể có một đoạn mã nhỏ chạy liên tục, đẩy các tin nhắn từ đầu đọc NFC vào hàng đợi tin nhắn, sau đó Celery đọc và chuyển tiếp tới Django? Việc thiết lập và phân tích một chương trình nhỏ, ngay cả khi nó được viết bằng Python (chứ không phải Django!), Tốt hơn là bắt đầu và dừng chương trình Django (với tất cả các hệ thống con của nó).
Tôi không chắc máy chủ web nào bạn đang sử dụng cho Django. mod_wsgi
cho Apache cho phép bạn định cấu hình số lượng quy trình và luồng trong các quy trình mà dịch vụ yêu cầu. Hãy chắc chắn điều chỉnh cấu hình có liên quan của máy chủ web của bạn để tối ưu hóa số lượng yêu cầu có thể dịch vụ.
2. Truyền tin nhắn qua mạng với tín hiệu Django
Trường hợp sử dụng thứ hai của bạn cũng khá thú vị; Tôi không chắc mình có câu trả lời cho điều đó không. Nếu bạn đang xóa các phiên bản mô hình và muốn hoạt động trên chúng sau này, có thể tuần tự hóa chúng JSON.dumps
và sau đó giải tuần tự hóa JSON.loads
. Sau này không thể tạo lại hoàn toàn biểu đồ đối tượng (truy vấn các mô hình liên quan), vì các trường liên quan được tải lười biếng từ cơ sở dữ liệu và liên kết đó sẽ không còn tồn tại.
Tùy chọn khác là bằng cách nào đó đánh dấu một đối tượng để xóa và chỉ xóa nó ở cuối chu kỳ yêu cầu / phản hồi (sau khi tất cả các tín hiệu đã được phục vụ). Nó có thể yêu cầu một tín hiệu tùy chỉnh để thực hiện điều này, thay vì dựa vào post_delete
.