Đồng thời: Làm thế nào để bạn tiếp cận thiết kế và gỡ lỗi thực hiện?


37

Tôi đã phát triển các hệ thống đồng thời trong vài năm nay và tôi đã nắm bắt khá tốt về vấn đề này mặc dù tôi không được đào tạo chính quy (tức là không có bằng cấp). Có một vài ngôn ngữ mới đã trở nên phổ biến ít nhất là nói về gần đây được thiết kế để làm cho việc đồng thời dễ dàng hơn như Erlang và Go. Dường như cách tiếp cận đồng thời của họ lặp lại trải nghiệm của riêng tôi về cách làm cho các hệ thống có thể mở rộng và tận dụng nhiều lõi / bộ xử lý / máy.

Tuy nhiên, tôi thấy rằng có rất ít công cụ giúp hình dung những gì bạn định làm và xác minh rằng bạn ít nhất là gần với tầm nhìn ban đầu của bạn. Gỡ lỗi mã đồng thời có thể là một cơn ác mộng với các ngôn ngữ không được thiết kế cho đồng thời (như C / C ++, C #, Java, v.v.). Đặc biệt, gần như không thể tạo lại các điều kiện xảy ra dễ dàng trên một hệ thống trong môi trường phát triển của bạn.

Vì vậy, cách tiếp cận của bạn để thiết kế một hệ thống để đối phó với xử lý đồng thời và xử lý song song là gì? Ví dụ:

  • Làm thế nào để bạn tìm ra những gì có thể được thực hiện đồng thời so với những gì phải được tuần tự?
  • Làm thế nào để bạn tái tạo các điều kiện lỗi và xem những gì đang xảy ra khi ứng dụng thực thi?
  • Làm thế nào để bạn hình dung các tương tác giữa các phần đồng thời khác nhau của ứng dụng?

Tôi có câu trả lời của riêng mình cho một số trong số này, nhưng tôi cũng muốn tìm hiểu thêm một chút.

Chỉnh sửa

Cho đến nay chúng ta có rất nhiều đầu vào tốt. Nhiều bài viết được liên kết đến là rất tốt, và tôi đã đọc một số trong số chúng.

Kinh nghiệm cá nhân của tôi với lập trình đồng thời khiến tôi tin rằng bạn cần một tư duy khác với bạn làm với lập trình tuần tự. Sự phân chia về mặt tinh thần có lẽ rộng bằng sự khác biệt giữa lập trình hướng đối tượng và lập trình thủ tục. Tôi muốn bộ câu hỏi này tập trung hơn vào các quá trình suy nghĩ cần thiết (tức là lý thuyết) để tiếp cận một cách có hệ thống các câu trả lời. Khi cung cấp câu trả lời cụ thể hơn, nó giúp cung cấp một ví dụ - một cái gì đó bạn đã trải qua cá nhân.

Mục tiêu cho tiền thưởng

Đừng nói với tôi những gì tôi nên làm. Tôi đã kiểm soát được điều đó. Kể cho tôi bạn làm gì. Hãy cho tôi biết làm thế nào bạn giải quyết những vấn đề này.


Đây là một câu hỏi hay - rất nhiều chiều sâu có thể. Tôi cũng đã nhận được một số kinh nghiệm tốt với các ứng dụng đa luồng trong Java, nhưng muốn tìm hiểu thêm.
Michael K

Cho đến nay, chúng tôi có một vài câu trả lời tốt. Bất cứ ai cũng muốn mạo hiểm đâm vào những gì bạn muốn bạn phải giúp bạn trong lĩnh vực này?
Berin Loritsch

TotalView Debugger để mã hóa đồng thời là một công cụ khá hữu ích, mặc dù có một chút về đường cong học tập - Totalviewtech.com/products/totalview.html
Fanatic23

Có lẽ đăng nhập có thể giúp bạn với hai câu hỏi cuối cùng.
Amir Rezaei

Những gì tôi đang tìm kiếm là quá trình của mọi người. Đây là những lĩnh vực mà các công cụ tôi đang sử dụng không đầy đủ, nhưng có thể hoàn thành công việc. Tôi ít quan tâm đến việc trích dẫn bài báo của người khác và quan tâm nhiều hơn đến phương pháp luận ở đây.
Berin Loritsch

Câu trả lời:


11

Tôi đã phát triển các hệ thống đồng thời trong vài năm nay và tôi đã nắm bắt khá tốt về vấn đề này mặc dù tôi không được đào tạo chính quy (tức là không có bằng cấp).

Nhiều lập trình viên giỏi nhất mà tôi biết đã không học xong Đại học. Đối với tôi, tôi học Triết học.

C / C ++, C #, Java, v.v.). Đặc biệt, gần như không thể tạo lại các điều kiện xảy ra dễ dàng trên một hệ thống trong môi trường phát triển của bạn.

Vâng

Làm thế nào để bạn tìm ra những gì có thể được thực hiện đồng thời so với những gì phải được tuần tự?

chúng ta thường bắt đầu với 1000 dặm ẩn dụ cao để làm rõ kiến ​​trúc của chúng tôi để chúng ta (trước hết) và cho người khác (thứ hai).

Khi chúng tôi đối mặt với vấn đề đó, chúng tôi luôn tìm cách hạn chế khả năng hiển thị của các đối tượng đồng thời với các đối tượng không đồng thời.

Gần đây tôi phát hiện ra Diễn viên trong scala và tôi thấy rằng các giải pháp cũ của tôi là một loại "miniactors", ít mạnh hơn nhiều so với scala. Vì vậy, đề nghị của tôi là bắt đầu từ đó.

Một đề xuất khác là bỏ qua càng nhiều vấn đề càng tốt: ví dụ: chúng tôi sử dụng bộ đệm tập trung (đất nung) thay vì giữ bản đồ trong bộ nhớ, sử dụng các cuộc gọi lại lớp bên trong thay vì phương thức đồng bộ hóa, gửi tin nhắn thay vì viết bộ nhớ chia sẻ, v.v.

Với scala, mọi thứ dễ dàng hơn nhiều.

Làm thế nào để bạn tái tạo các điều kiện lỗi và xem những gì đang xảy ra khi ứng dụng thực thi?

Không có câu trả lời thực sự ở đây. Chúng tôi có một số thử nghiệm đơn vị cho đồng thời và chúng tôi có một bộ thử tải để nhấn mạnh ứng dụng nhiều nhất có thể.

Làm thế nào để bạn hình dung các tương tác giữa các phần đồng thời khác nhau của ứng dụng?

Một lần nữa không có câu trả lời thực sự: chúng tôi thiết kế Ẩn dụ của chúng tôi trên bảng trắng và chúng tôi cố gắng đảm bảo không có xung đột về phía kiến ​​trúc.

Đối với Arch ở đây tôi muốn nói đến định nghĩa của Neal Ford: Sw Architecture là mọi thứ sẽ rất khó thay đổi sau này.

lập trình khiến tôi tin rằng bạn cần một tư duy khác với bạn làm với lập trình tuần tự.

Có thể nhưng đối với tôi đơn giản là không thể suy nghĩ theo cách song song, vì vậy tốt hơn là thiết kế phần mềm của chúng tôi theo cách không yêu cầu suy nghĩ song song và có các rào chắn rõ ràng để tránh sự cố giữa các làn đường đồng thời.


6

Đối với tôi là tất cả về dữ liệu. Phá vỡ dữ liệu của bạn ngay, và xử lý song song là dễ dàng. Tất cả các vấn đề với duy trì, bế tắc, và vì vậy đi.

Tôi biết rằng đây không phải là cách duy nhất để song song, nhưng đối với tôi là hữu ích nhất.

Để minh họa, một câu chuyện (không quá nhanh):

Tôi đã làm việc trên một hệ thống tài chính lớn (kiểm soát thị trường chứng khoán) từ năm 2007 đến năm 2009 và khối lượng xử lý dữ liệu rất lớn. Để minh họa, tất cả các tính toán được thực hiện cho 1 tài khoản của một khách hàng mất khoảng 1 ~ 3 giây trên máy trạm trung bình của họ và có hơn 30k tài khoản. Mỗi đêm, việc đóng hệ thống là một nỗi đau lớn đối với người dùng (thường là hơn 6 giờ xử lý, không có bất kỳ lỗi nào đối với họ).

Nghiên cứu vấn đề tiếp tục tiết lộ rằng chúng ta có thể làm tê liệt các tính toán giữa một số máy tính, nhưng chúng ta vẫn sẽ có một nút cổ chai lớn trên máy chủ cơ sở dữ liệu cũ (máy chủ SQL 2000 mô phỏng SQL 6.5).

Rõ ràng là gói xử lý tối thiểu của chúng tôi là tính toán của một tài khoản và nút cổ chai chính là sự lưu giữ máy chủ cơ sở dữ liệu (chúng tôi có thể thấy trên một số kết nối đang chờ xử lý tương tự). Vì vậy, quá trình song song diễn ra như sau:

1) Một nhà sản xuất duy nhất, chịu trách nhiệm đọc cơ sở dữ liệu hoặc viết trên đó, theo tuần tự. Không cho phép đồng thời ở đây. Nhà sản xuất đã chuẩn bị một loạt các công việc, cho người tiêu dùng. Cơ sở dữ liệu chỉ thuộc về nhà sản xuất này.

2) Một số người tiêu dùng, trên một số máy. Mỗi người tiêu dùng nhận được toàn bộ gói dữ liệu, từ hàng đợi, sẵn sàng tính toán. Mỗi hoạt động deqeue được đồng bộ hóa.

3) Sau khi tính toán, mỗi người tiêu dùng đã gửi lại dữ liệu vào hàng đợi được đồng bộ hóa trong bộ nhớ cho nhà sản xuất, để duy trì dữ liệu.

Có một số điểm kiểm tra, một số cơ chế để đảm bảo các giao dịch được lưu chính xác (không có điểm nào bị bỏ lại phía sau), nhưng toàn bộ công việc đều đáng giá. Cuối cùng, các tính toán trải đều giữa 10 máy tính (cộng với máy tính của nhà sản xuất / hàng đợi) đã giảm thời gian đóng cửa toàn bộ hệ thống xuống còn 15 phút.

Chỉ cần loại bỏ các vấn đề duy trì do quản lý tương tranh kém SQL 6.5 đã mang lại cho chúng tôi một lợi thế lớn. Phần còn lại là khá tuyến tính, mỗi máy tính mới được thêm vào "lưới" làm giảm thời gian xử lý, cho đến khi chúng tôi đạt được "hiệu quả tối đa" của các hoạt động đọc / ghi tuần tự trên cơ sở dữ liệu.


2

Làm việc trong môi trường đa luồng là khó khăn và cần kỷ luật mã hóa. Bạn cần tuân theo hướng dẫn thích hợp để lấy khóa, giải phóng khóa, truy cập các biến toàn cục, v.v.

Hãy để tôi cố gắng trả lời câu hỏi của bạn từng cái một

* How do you figure out what can be made concurrent vs. what has to be sequential?

Sử dụng đồng thời cho

1) Bỏ phiếu: - cần một chủ đề để liên tục bỏ phiếu một cái gì đó hoặc gửi cập nhật thường xuyên. (Các khái niệm như bit-heart, gửi một số dữ liệu trên khoảng thời gian thường xuyên đến máy chủ trung tâm để nói rằng tôi còn sống.)

2) Các hoạt động có i / o nặng có thể được thực hiện song song. Ví dụ tốt nhất là logger. Các luồng logger có thể là một luồng riêng biệt.

3) Nhiệm vụ tương tự trên các dữ liệu khác nhau. Nếu có một số tác vụ xảy ra trên các dữ liệu khác nhau nhưng về bản chất rất giống nhau, các luồng khác nhau có thể thực hiện việc này. Ví dụ tốt nhất sẽ là yêu cầu máy chủ.

Và tất nhiên nhiều người khác thích điều này tùy thuộc vào ứng dụng.

* How do you reproduce error conditions and view what is happening as the application executes?

Sử dụng nhật ký và gỡ lỗi in trong nhật ký. Cố gắng đăng nhập id chủ đề để bạn có thể thấy những gì đang xảy ra trong mỗi luồng.
Một cách để tạo ra tình trạng lỗi là đặt độ trễ có chủ ý (trong mã gỡ lỗi) ở những nơi bạn nghĩ rằng sự cố đang xảy ra và buộc dừng luồng đó. Những điều tương tự cũng có thể được thực hiện trong trình gỡ lỗi, nhưng tôi đã không làm điều đó cho đến nay.

* How do you visualize the interactions between the different concurrent parts of the application?

Đặt nhật ký vào ổ khóa của bạn, để bạn sẽ biết ai đang khóa cái gì và khi nào, và ai đã thử khóa. Như tôi đã nói trước đó, cố gắng đưa id luồng vào nhật ký để hiểu những gì đang diễn ra trong mỗi luồng.

Đây chỉ là lời khuyên của tôi trong khoảng 3 năm làm việc trên ứng dụng đa luồng và hy vọng nó có ích.


2
  • Làm thế nào để bạn tìm ra những gì có thể được thực hiện đồng thời so với những gì phải được tuần tự?

Trước tiên tôi sẽ đặt câu hỏi liệu ứng dụng (hoặc thành phần) sẽ thực sự thấy được lợi ích từ việc xử lý đồng thời hay theo thuật ngữ của giáo dân - nút thắt ở đâu? Đồng thời rõ ràng sẽ không luôn luôn cung cấp một lợi ích cho khoản đầu tư cần thiết để làm cho nó hoạt động. Nếu nó trông giống như một ứng cử viên, thì tôi sẽ làm việc từ dưới lên - cố gắng tìm ra hoạt động lớn nhất hoặc tập hợp các hoạt động có thể thực hiện công việc của nó một cách hiệu quả - tôi không muốn quay vòng các chủ đề cho không đáng kể, không hiệu quả hoạt động - Tôi đang tìm diễn viên .

Làm việc với Erlang Tôi hoàn toàn thích khái niệm sử dụng thông điệp không đồng bộ và mô hình diễn viên để đồng thời - nó trực quan, hiệu quả và rõ ràng.

Tắt các truy cập đồng thời diễn viên Hiểu

Mô hình diễn viên bao gồm một vài nguyên tắc chính:

  • Không có trạng thái chia sẻ
  • Quy trình nhẹ
  • Truyền tin nhắn không đồng bộ
  • Hộp thư để đệm thư đến
  • Xử lý hộp thư với khớp mẫu

Một diễn viên là một quá trình thực thi một chức năng. Ở đây một quy trình là một luồng không gian người dùng nhẹ (không bị nhầm lẫn với một quy trình hệ điều hành nặng ký điển hình). Các diễn viên không bao giờ chia sẻ trạng thái và do đó không bao giờ cần phải cạnh tranh cho các khóa để truy cập vào dữ liệu được chia sẻ. Thay vào đó, các diễn viên chia sẻ dữ liệu bằng cách gửi tin nhắn bất biến. Dữ liệu không thay đổi không thể được sửa đổi, vì vậy việc đọc không yêu cầu khóa.

Mô hình đồng thời Erlang dễ hiểu và gỡ lỗi hơn so với khóa và chia sẻ dữ liệu. Cách thức mà logic của bạn được phân lập giúp dễ dàng thực hiện kiểm tra các thành phần bằng cách gửi tin nhắn cho chúng.

Làm việc với các hệ thống đồng thời, đây là cách mà thiết kế của tôi hoạt động với bất kỳ ngôn ngữ nào - một hàng đợi có nhiều luồng sẽ lấy dữ liệu từ đó, thực hiện một thao tác đơn giản và lặp lại hoặc đẩy trở lại hàng đợi. Erlang chỉ thực thi các cấu trúc dữ liệu bất biến để ngăn chặn các tác dụng phụ và giảm chi phí và độ phức tạp của việc tạo các luồng mới.

Mô hình này không phải là độc quyền của Erlang, ngay cả trong thế giới Java và .NET vẫn tồn tại các cách để tạo ra điều này - tôi sẽ xem xét Thời gian chạy đồng thời và phối hợp (CCR)Relang (cũng có Jetlang cho Java).

  • Làm thế nào để bạn tái tạo các điều kiện lỗi và xem những gì đang xảy ra khi ứng dụng thực thi?

Theo kinh nghiệm của tôi, điều duy nhất tôi có thể làm là đưa ra một cam kết truy tìm / ghi nhật ký mọi thứ. Mỗi quy trình / luồng cần phải có một định danh và mỗi đơn vị công việc mới cần phải có id tương quan. Bạn cần có thể xem qua nhật ký của mình và theo dõi chính xác những gì đang được xử lý và khi nào - không có phép thuật nào tôi từng thấy để loại bỏ điều này.

  • Làm thế nào để bạn hình dung các tương tác giữa các phần đồng thời khác nhau của ứng dụng?

Xem ở trên, nó xấu nhưng nó hoạt động. Điều khác duy nhất tôi làm là sử dụng các sơ đồ trình tự UML - tất nhiên điều này là trong thời gian thiết kế - nhưng bạn có thể sử dụng chúng để xác minh rằng các thành phần của bạn đang nói theo cách bạn muốn.


1

- Câu trả lời của tôi là MS / Visual Studio cụ thể -

Làm thế nào để bạn tìm ra những gì có thể được thực hiện đồng thời so với những gì phải được tuần tự?

Điều đó sẽ lấy kiến ​​thức tên miền, sẽ không có bất kỳ tuyên bố nào ở đây để che đậy nó.

Làm thế nào để bạn tái tạo các điều kiện lỗi và xem những gì đang xảy ra khi ứng dụng thực thi?

Rất nhiều đăng nhập, có thể bật / tắt / đăng nhập trong các ứng dụng sản xuất để bắt nó vào sản xuất. VS2010 Intellitrace được cho là có thể giúp với điều này, nhưng tôi chưa sử dụng nó.

Làm thế nào để bạn hình dung các tương tác giữa các phần đồng thời khác nhau của ứng dụng?

Tôi không có câu trả lời tốt cho vấn đề này, rất thích nhìn thấy một.


Ghi nhật ký sẽ thay đổi cách mã thực thi và do đó có thể dẫn đến lỗi bạn gặp phải sau khi không hiển thị.
Matthew đọc

1

Tôi không đồng ý với tuyên bố của bạn rằng C không được thiết kế để tương tranh. C được thiết kế để lập trình hệ thống chung và thích sự kiên trì để chỉ ra các quyết định quan trọng được đưa ra, và sẽ tiếp tục làm như vậy trong nhiều năm tới. Điều này đúng ngay cả khi quyết định tốt nhất có thể không sử dụng C. Ngoài ra, đồng thời trong C chỉ khó khăn khi thiết kế của bạn phức tạp.

Tôi cố gắng, để tốt nhất khả năng của mình, để thực hiện khóa với ý tưởng rằng cuối cùng, thật sự thực tế khóa lập trình miễn phí có thể trở thành hiện thực đối với tôi. Bằng cách khóa, tôi không có nghĩa là loại trừ lẫn nhau, tôi chỉ đơn giản là một quá trình thực hiện đồng thời an toàn mà không cần phải phân xử. Theo thực tế, tôi có nghĩa là một cái gì đó dễ dàng chuyển hơn so với nó được thực hiện. Tôi cũng có rất ít khóa đào tạo CS chính thức, nhưng tôi cho rằng tôi được phép ước :)

Theo đó, hầu hết các lỗi mà tôi gặp phải trở nên tương đối nông cạn, hoặc hoàn toàn bận tâm đến việc tôi rút lui đến một quán rượu. Quán rượu chỉ trở thành một lựa chọn hấp dẫn khi cấu hình một chương trình làm chậm nó đủ để lộ ra các cuộc đua bổ sung không liên quan đến những gì tôi đang cố gắng tìm kiếm.

Như những người khác đã chỉ ra, vấn đề mà bạn mô tả là cực kỳ cụ thể về miền. Tôi chỉ cố gắng, với khả năng tốt nhất của mình để tránh mọi trường hợp có thể yêu cầu phân xử (ngoài quy trình của tôi) bất cứ khi nào có thể. Nếu điều đó có vẻ như là một nỗi đau vương giả, tôi đánh giá lại tùy chọn cung cấp nhiều luồng hoặc quá trình truy cập đồng thời và không được kiểm duyệt vào một cái gì đó.

Sau đó, một lần nữa, ném 'phân phối' vào đó và trọng tài trở thành phải. Bạn có một ví dụ cụ thể?


Để làm rõ tuyên bố của tôi, C không được thiết kế riêng cho và xung quanh đồng thời. Điều này trái ngược với các ngôn ngữ như Go, Erlang và Scala được thiết kế rõ ràng với ý tưởng đồng thời. Tôi không có ý định nói rằng bạn không thể đồng thời với C.
Berin Loritsch

1

Làm thế nào để bạn tái tạo các điều kiện lỗi và xem những gì đang xảy ra khi ứng dụng thực thi?

Làm thế nào để bạn hình dung các tương tác giữa các phần đồng thời khác nhau của ứng dụng?

Dựa trên kinh nghiệm của tôi, câu trả lời cho hai khía cạnh này như sau:

Truy tìm phân tán

Truy tìm phân tán là công nghệ thu thập dữ liệu thời gian cho từng thành phần đồng thời riêng lẻ trong hệ thống của bạn và trình bày cho bạn ở định dạng đồ họa. Các đại diện của các thực thi đồng thời luôn được xen kẽ, cho phép bạn xem những gì đang chạy song song và những gì không.

Truy tìm phân tán nợ nguồn gốc của nó trong (tất nhiên) các hệ thống phân tán, theo định nghĩa là không đồng bộ và đồng thời cao. Một hệ thống phân tán với theo dõi phân tán cho phép mọi người:

a) xác định các tắc nghẽn quan trọng, b) có được biểu thị trực quan về 'chạy' lý tưởng của ứng dụng của bạn và c) cung cấp khả năng hiển thị về hành vi đồng thời đang được thực thi, d) có được dữ liệu thời gian có thể được sử dụng để đánh giá sự khác biệt giữa các thay đổi trong hệ thống (cực kỳ quan trọng nếu bạn có SLA mạnh).

Tuy nhiên, hậu quả của truy tìm phân tán là:

  1. Nó thêm chi phí cho tất cả các quy trình đồng thời của bạn, vì nó chuyển thành nhiều mã hơn để thực thi và gửi tiềm năng qua mạng. Trong một số trường hợp, chi phí này rất có ý nghĩa - thậm chí Google chỉ sử dụng hệ thống theo dõi của họ Dapper trên một tập hợp nhỏ của tất cả các yêu cầu để không làm hỏng trải nghiệm người dùng.

  2. Nhiều công cụ khác nhau tồn tại, không phải tất cả đều có thể tương tác với nhau. Điều này có phần được cải thiện bởi các tiêu chuẩn như OpenTracing, nhưng không được giải quyết hoàn toàn.

  3. Nó không cho bạn biết về tài nguyên được chia sẻ và tình trạng hiện tại của chúng. Bạn có thể đoán, dựa trên mã ứng dụng và biểu đồ bạn thấy đang hiển thị cho bạn, nhưng nó không phải là một công cụ hữu ích trong vấn đề này.

  4. Các công cụ hiện tại giả định rằng bạn có bộ nhớ và lưu trữ dự phòng. Lưu trữ một máy chủ thời gian có thể không rẻ, tùy thuộc vào các ràng buộc của bạn.

Phần mềm theo dõi lỗi

Tôi liên kết với Sentry ở trên chủ yếu vì đây là công cụ được sử dụng rộng rãi nhất hiện nay và vì lý do chính đáng - phần mềm theo dõi lỗi như Sentry chiếm quyền điều khiển thời gian chạy để đồng thời chuyển tiếp dấu vết lỗi của máy chủ trung tâm.

Lợi ích ròng của phần mềm chuyên dụng như vậy trong mã đồng thời:

  1. Lỗi trùng lặp không được nhân đôi . Nói cách khác, nếu một hoặc nhiều hệ thống đồng thời gặp phải ngoại lệ tương tự, Sentry sẽ tăng báo cáo sự cố, nhưng không gửi hai bản sao của sự cố.

Điều này có nghĩa là bạn có thể tìm ra hệ thống đồng thời đang gặp loại lỗi nào mà không phải trải qua vô số báo cáo lỗi đồng thời. Nếu bạn đã từng bị spam email từ một hệ thống phân tán, bạn sẽ biết cảm giác như thế nào.

Bạn thậm chí có thể 'gắn thẻ' các khía cạnh khác nhau của hệ thống đồng thời của mình (mặc dù điều này giả định rằng bạn không làm việc xen kẽ với chính xác một luồng, dù về mặt kỹ thuật không phải là đồng thời vì luồng chỉ đơn giản là nhảy giữa các tác vụ một cách hiệu quả nhưng vẫn phải xử lý các trình xử lý sự kiện để hoàn thành) và xem bảng phân tích các lỗi theo thẻ.

  1. Bạn có thể sửa đổi phần mềm xử lý lỗi này để cung cấp thêm chi tiết với các ngoại lệ thời gian chạy của bạn. Những tài nguyên mở đã làm quá trình có? Có một tài nguyên được chia sẻ mà quá trình này đang nắm giữ? Người dùng nào gặp vấn đề này?

Điều này, ngoài các dấu vết ngăn xếp tỉ mỉ (và bản đồ nguồn, nếu bạn phải cung cấp một phiên bản rút gọn của các tệp của mình), giúp bạn dễ dàng xác định điều gì sẽ xảy ra trong một phần lớn thời gian.

  1. (Cụ thể về Sentry) Bạn có thể có bảng điều khiển báo cáo Sentry riêng để chạy thử hệ thống, cho phép bạn bắt lỗi trong quá trình kiểm tra.

Những nhược điểm của phần mềm này bao gồm:

  1. Giống như mọi thứ, họ thêm số lượng lớn. Bạn có thể không muốn một hệ thống như vậy trên phần cứng nhúng, ví dụ. Tôi đặc biệt khuyên bạn nên chạy thử phần mềm như vậy, so sánh một thực thi đơn giản với và không có phần mềm được lấy mẫu trong vài trăm lần chạy trên một máy nhàn rỗi.

  2. Không phải tất cả các ngôn ngữ đều được hỗ trợ như nhau, vì nhiều hệ thống trong số này dựa vào việc bắt một ngoại lệ và không phải tất cả các ngôn ngữ đều có ngoại lệ mạnh mẽ. Điều đó đang được nói, có khách hàng cho rất nhiều hệ thống.

  3. Chúng có thể được coi là một rủi ro bảo mật, vì nhiều trong số các hệ thống này về cơ bản là nguồn đóng. Trong những trường hợp như vậy, hãy chăm chỉ nghiên cứu chúng, hoặc, nếu được ưa thích, hãy tự mình lăn lộn.

  4. Họ có thể không luôn luôn cung cấp cho bạn thông tin bạn cần. Đây là một rủi ro với tất cả các nỗ lực để thêm khả năng hiển thị.

  5. Hầu hết các dịch vụ này được thiết kế cho các ứng dụng web có tính đồng thời cao, vì vậy không phải mọi công cụ đều có thể hoàn hảo cho trường hợp sử dụng của bạn.

Tóm lại : có khả năng hiển thị là phần quan trọng nhất của bất kỳ hệ thống đồng thời nào. Hai phương pháp tôi mô tả ở trên, kết hợp với bảng điều khiển chuyên dụng về phần cứng và dữ liệu để có được một bức tranh toàn diện về hệ thống tại bất kỳ mốc thời gian cụ thể nào, được sử dụng rộng rãi trong toàn ngành để giải quyết chính xác khía cạnh đó.

Một số gợi ý bổ sung

Tôi đã dành nhiều thời gian hơn tôi quan tâm đến việc sửa mã bởi những người đã cố gắng giải quyết các vấn đề đồng thời theo những cách khủng khiếp. Mỗi lần, tôi đã tìm thấy những trường hợp trong đó những điều sau đây có thể cải thiện đáng kể trải nghiệm của nhà phát triển (điều này cũng quan trọng như trải nghiệm người dùng):

  • Dựa vào các loại . Nhập vào tồn tại để xác thực mã của bạn và có thể được sử dụng trong thời gian chạy như một bảo vệ bổ sung. Trường hợp gõ không tồn tại, hãy dựa vào các xác nhận và trình xử lý lỗi phù hợp để bắt lỗi. Mã đồng thời yêu cầu mã phòng thủ và các loại đóng vai trò là loại xác nhận tốt nhất hiện có.

    • Kiểm tra liên kết giữa các thành phần mã , không chỉ chính thành phần đó. Đừng nhầm lẫn điều này với một bài kiểm tra tích hợp toàn diện - kiểm tra mọi liên kết giữa mọi thành phần, và thậm chí sau đó nó chỉ tìm kiếm một xác nhận toàn cầu về trạng thái cuối cùng. Đây là một cách khủng khiếp để bắt lỗi.

Một tốt kiểm tra liên kết sẽ kiểm tra xem, khi một cuộc đàm phán thành phần để một thành phần trong sự cô lập , các tin nhắn đã nhận và gửi tin nhắn là aa cùng bạn mong đợi. Nếu bạn có hai hoặc nhiều thành phần dựa vào dịch vụ chia sẻ để liên lạc, hãy quay vòng tất cả, yêu cầu họ trao đổi tin nhắn qua dịch vụ trung tâm và xem cuối cùng họ có nhận được những gì bạn mong đợi không.

Việc chia nhỏ các bài kiểm tra liên quan đến rất nhiều thành phần để tự kiểm tra các thành phần và kiểm tra xem mỗi thành phần giao tiếp với nhau như thế nào cũng giúp bạn tăng sự tin cậy về tính hợp lệ của mã. Việc có các bài kiểm tra nghiêm ngặt như vậy cho phép bạn thực thi các hợp đồng giữa các dịch vụ cũng như nắm bắt các lỗi không mong muốn xảy ra khi chúng chạy cùng một lúc.

  • Sử dụng các thuật toán phù hợp để xác nhận trạng thái ứng dụng của bạn. Tôi đang nói về những điều đơn giản, chẳng hạn như khi bạn có một quy trình tổng thể chờ tất cả nhân viên của mình hoàn thành một nhiệm vụ và chỉ muốn chuyển sang bước tiếp theo nếu tất cả các công nhân đã hoàn thành - đây là một ví dụ về phát hiện toàn cầu chấm dứt, tồn tại các phương pháp đã biết như thuật toán của Safra.

Một số trong các công cụ này đi kèm với các ngôn ngữ - chẳng hạn, Rust, đảm bảo mã của bạn sẽ không có điều kiện chạy đua trong thời gian biên dịch, trong khi Go có trình phát hiện khóa chết sẵn có cũng chạy trong thời gian biên dịch. Nếu bạn có thể nắm bắt các vấn đề trước khi chúng được sản xuất, nó luôn luôn là một chiến thắng.

Một nguyên tắc chung: thiết kế cho sự thất bại trong các hệ thống đồng thời . Dự đoán rằng các dịch vụ phổ biến sẽ sụp đổ hoặc phá vỡ. Điều này diễn ra ngay cả đối với mã không được phân phối trên các máy - mã đồng thời trên một máy có thể phụ thuộc vào các phụ thuộc bên ngoài (như tệp nhật ký dùng chung, máy chủ Redis, máy chủ MySQL chết tiệt) có thể biến mất hoặc bị xóa bất cứ lúc nào .

Cách tốt nhất để làm điều này là thỉnh thoảng xác nhận trạng thái ứng dụng - kiểm tra sức khỏe cho từng dịch vụ và đảm bảo người tiêu dùng của dịch vụ đó được thông báo về tình trạng sức khỏe xấu. Các công cụ container hiện đại như Docker làm điều này khá tốt, và nên được sử dụng để làm các thứ trong hộp cát.

Làm thế nào để bạn tìm ra những gì có thể được thực hiện đồng thời và những gì có thể được thực hiện tuần tự?

Một trong những bài học lớn nhất tôi học được khi làm việc trên một hệ thống đồng thời cao là: bạn không bao giờ có thể có đủ số liệu . Số liệu sẽ điều khiển hoàn toàn mọi thứ trong ứng dụng của bạn - bạn không phải là kỹ sư nếu bạn không đo lường mọi thứ.

Không có số liệu, bạn không thể làm một vài điều rất quan trọng:

  1. Đánh giá sự khác biệt được thực hiện bởi những thay đổi cho hệ thống. Nếu bạn không biết nếu nút điều chỉnh A làm cho số liệu B tăng lên và số liệu C giảm xuống, bạn không biết cách khắc phục hệ thống của mình khi mọi người đẩy mã ác tính bất ngờ trên hệ thống của bạn (và họ sẽ đẩy mã vào hệ thống của bạn) .

  2. Hiểu những gì bạn cần làm tiếp theo để cải thiện mọi thứ. Cho đến khi bạn biết các ứng dụng sắp hết bộ nhớ, bạn không thể biết liệu bạn nên lấy thêm bộ nhớ hay mua thêm đĩa cho máy chủ của mình.

Các số liệu rất quan trọng và thiết yếu đến nỗi tôi đã biến nó thành một nỗ lực có ý thức để lên kế hoạch cho những gì tôi muốn đo trước khi tôi nghĩ về những gì một hệ thống sẽ yêu cầu. Trong thực tế, các số liệu rất quan trọng đến nỗi tôi tin rằng chúng là câu trả lời đúng cho câu hỏi này: bạn chỉ biết những gì có thể được thực hiện tuần tự hoặc đồng thời khi bạn đo lường các bit trong chương trình của bạn đang làm gì. Thiết kế phù hợp sử dụng số, không phỏng đoán.

Điều đó đang được nói, chắc chắn có một vài quy tắc của ngón tay cái:

  1. Tuần tự ngụ ý sự phụ thuộc. Hai quá trình nên được tuần tự nếu một phụ thuộc vào nhau trong một số thời trang. Các quy trình không có phụ thuộc nên được đồng thời. Tuy nhiên, lập kế hoạch một cách để xử lý luồng không thành công mà không ngăn chặn các quá trình xuôi dòng chờ đợi vô thời hạn.

  2. Không bao giờ trộn lẫn một nhiệm vụ ràng buộc I / O với một nhiệm vụ gắn với CPU trên cùng một lõi. Đừng (ví dụ) viết trình thu thập dữ liệu web khởi chạy mười yêu cầu đồng thời trong cùng một chuỗi, loại bỏ chúng ngay khi chúng đến và dự kiến ​​sẽ mở rộng đến năm trăm - yêu cầu I / O đi đến hàng đợi song song, nhưng CPU vẫn sẽ đi qua chúng một cách an toàn. (Mô hình hướng sự kiện đơn luồng này là một mô hình phổ biến, nhưng nó bị hạn chế do khía cạnh này - thay vì hiểu điều này, mọi người chỉ cần vặn tay và nói Node không mở rộng quy mô, để cho bạn một ví dụ).

Một chủ đề duy nhất có thể làm rất nhiều công việc I / O. Nhưng để sử dụng hoàn toàn đồng thời phần cứng của bạn, hãy sử dụng các chuỗi kết hợp với nhau chiếm tất cả các lõi. Trong ví dụ trên, khởi chạy năm quy trình Python (mỗi quy trình có thể sử dụng lõi trên máy sáu lõi) chỉ dành cho công việc CPU và luồng Python thứ sáu chỉ dành cho công việc I / O sẽ mở rộng nhanh hơn nhiều so với bạn nghĩ.

Cách duy nhất để tận dụng lợi thế đồng thời của CPU là thông qua một luồng chuyên dụng. Một chủ đề thường đủ tốt cho nhiều công việc ràng buộc I / O. Đây là lý do tại sao các máy chủ web điều khiển sự kiện như Nginx có quy mô tốt hơn (chúng hoàn toàn làm việc liên kết I / O) so với Apache (kết hợp công việc ràng buộc I / O với thứ gì đó yêu cầu CPU và khởi chạy quy trình theo yêu cầu), nhưng tại sao sử dụng Node để thực hiện Hàng chục ngàn phép tính GPU nhận được song song là một ý tưởng tồi tệ .


0

Vâng, đối với quá trình xác minh, khi thiết kế một hệ thống đồng thời lớn - tôi có xu hướng kiểm tra mô hình bằng LTSA - Bộ phân tích hệ thống chuyển đổi có nhãn . Nó được phát triển bởi gia sư cũ của tôi, một người kỳ cựu trong lĩnh vực đồng thời và là Trưởng phòng Điện toán tại Imperial.

Theo như tìm ra những gì có thể và không thể đồng thời, có những máy phân tích tĩnh có thể cho thấy rằng tôi tin, mặc dù tôi có xu hướng chỉ vẽ sơ đồ lập lịch cho các phần quan trọng, giống như bạn quản lý dự án. Sau đó xác định các phần thực hiện cùng một hoạt động lặp đi lặp lại. Một lộ trình nhanh chỉ là tìm các vòng lặp, vì chúng có xu hướng là các khu vực được hưởng lợi từ việc xử lý song song.


0

Làm thế nào để bạn tìm ra những gì có thể được thực hiện đồng thời so với những gì phải được tuần tự?

Khá nhiều thứ bạn viết có thể tận dụng đồng thời, đặc biệt là trường hợp sử dụng "dành một cuộc chinh phục". Một câu hỏi tốt hơn nhiều là những gì nên được đồng thời?

Threading của Joseph Albahari trong danh sách C # năm cách sử dụng phổ biến.

Đa luồng có nhiều công dụng; Dưới đây là phổ biến nhất:

Duy trì giao diện người dùng đáp ứng

Bằng cách chạy các tác vụ tiêu tốn thời gian trên luồng xử lý song song của công nhân, chủ đề UI chính có thể tự do tiếp tục xử lý các sự kiện bàn phím và chuột.

Sử dụng hiệu quả CPU bị chặn khác

Đa luồng rất hữu ích khi một luồng đang chờ phản hồi từ một máy tính hoặc phần cứng khác. Trong khi một luồng bị chặn trong khi thực hiện tác vụ, các luồng khác có thể tận dụng lợi thế của máy tính không bị gánh nặng.

Lập trình song song

Mã thực hiện các phép tính chuyên sâu có thể thực thi nhanh hơn trên các máy tính đa lõi hoặc đa bộ xử lý nếu khối lượng công việc được chia sẻ giữa nhiều luồng trong một chiến lược phân chia và chinh phục của người Viking (xem Phần 5).

Thi công đầu cơ

Trên các máy đa lõi, đôi khi bạn có thể cải thiện hiệu suất bằng cách dự đoán một số thứ có thể cần phải thực hiện và sau đó thực hiện trước thời hạn. LINQPad sử dụng kỹ thuật này để tăng tốc độ tạo các truy vấn mới. Một biến thể là chạy song song một số thuật toán khác nhau mà tất cả đều giải quyết cùng một nhiệm vụ. Bất cứ ai hoàn thành đầu tiên, bạn sẽ giành chiến thắng trong các trò chơi khác, bạn sẽ không thể biết trước thuật toán nào sẽ thực thi nhanh nhất.

Cho phép các yêu cầu được xử lý đồng thời

Trên máy chủ, các yêu cầu máy khách có thể đến đồng thời và do đó cần phải được xử lý song song (.NET Framework tự động tạo các luồng cho việc này nếu bạn sử dụng ASP.NET, WCF, Dịch vụ web hoặc Từ xa). Điều này cũng có thể hữu ích trên máy khách (ví dụ: xử lý mạng ngang hàng mạng hoặc thậm chí nhiều yêu cầu từ người dùng).

Nếu bạn không cố gắng thực hiện một trong những điều trên, có lẽ bạn nên suy nghĩ thực sự về nó.

Làm thế nào để bạn tái tạo các điều kiện lỗi và xem những gì đang xảy ra khi ứng dụng thực thi?

Nếu bạn đang sử dụng .NET và bạn đã sử dụng các trường hợp sử dụng bằng văn bản, bạn có thể sử dụng CHESS có thể tạo lại các điều kiện xen kẽ của luồng cụ thể cho phép bạn kiểm tra sửa lỗi của mình.

Làm thế nào để bạn hình dung các tương tác giữa các phần đồng thời khác nhau của ứng dụng?

Nó phụ thuộc vào ngữ cảnh. Đối với các kịch bản công nhân tôi nghĩ về một cấp dưới quản lý. Manger bảo cấp dưới làm gì đó và chờ cập nhật trạng thái.

Đối với các nhiệm vụ không liên quan đồng thời, tôi nghĩ về thang máy hoặc ô tô trong các làn đường giao thông riêng biệt.

Để đồng bộ hóa đôi khi tôi nghĩ về đèn giao thông hoặc kiểu rẽ.

Ngoài ra nếu bạn đang sử dụng C # 4.0, bạn có thể muốn xem Thư viện song song tác vụ


0

Câu trả lời của tôi cho câu hỏi này là:

  • Làm thế nào để bạn tìm ra những gì có thể được thực hiện đồng thời so với những gì phải được tuần tự?

Trước tiên tôi cần biết lý do tại sao tôi nên sử dụng đồng thời, bởi vì tôi đã phát hiện ra rằng mọi người đã thoát khỏi ý tưởng đằng sau sự tương tranh nhưng không phải lúc nào cũng nghĩ về vấn đề họ đang cố gắng giải quyết.

Nếu bạn phải mô phỏng một tình huống thực tế như hàng đợi, quy trình làm việc, v.v., rất có thể bạn sẽ cần sử dụng một cách tiếp cận đồng thời.

Bây giờ tôi biết rằng tôi nên sử dụng nó, đã đến lúc phân tích sự đánh đổi, nếu bạn có nhiều khoản xử lý, bạn có thể nghĩ về chi phí liên lạc, nhưng nếu bạn phải mới, có thể sẽ không có giải pháp đồng thời (vấn đề tái lập vì thế.)

  • Làm thế nào để bạn tái tạo các điều kiện lỗi và xem những gì đang xảy ra khi ứng dụng thực thi?

Tôi không có chuyên gia về vấn đề này nhưng tôi nghĩ rằng đối với các hệ thống đồng thời thì đây không phải là phương pháp đúng. Một cách tiếp cận lý thuyết nên được lựa chọn, tìm kiếm 4 yêu cầu bế tắc trên các lĩnh vực quan trọng:

  1. Không phòng ngừa
  2. Giữ và chờ
  3. Loại trừ động lực
  4. Chuỗi tròn

    • Làm thế nào để bạn hình dung các tương tác giữa các phần đồng thời khác nhau của ứng dụng?

Trước tiên tôi cố gắng xác định ai là người tham gia vào các tương tác, sau đó họ giao tiếp với ai và với ai. Cuối cùng, biểu đồ và sơ đồ tương tác giúp tôi hình dung. Bảng trắng cũ tốt của tôi không thể bị đánh bại bởi bất kỳ loại phương tiện truyền thông khác.


0

Tôi sẽ cùn. Tôi ngưỡng mộ các công cụ. Tôi sử dụng rất nhiều công cụ. Bước đầu tiên của tôi là bố trí các đường dẫn dự định cho dòng trạng thái. Bước tiếp theo của tôi là thử và tìm hiểu xem nó có đáng không, hoặc nếu luồng thông tin cần thiết sẽ khiến chuỗi mã quá thường xuyên. Sau đó, tôi sẽ thử và phác thảo một số mô hình đơn giản. Chúng có thể bao gồm từ một đống các tác phẩm điêu khắc tăm thô đến một số ví dụ đơn giản tương tự trong trăn. Tiếp theo, tôi xem qua một vài cuốn sách yêu thích của tôi, như cuốn sách nhỏ về ngữ nghĩa, và xem liệu ai đó đã đưa ra giải pháp tốt hơn cho vấn đề của tôi.

Sau đó tôi bắt đầu viết mã.
Đùa thôi. Nghiên cứu thêm một chút trước. Tôi thích ngồi xuống với một hacker đồng nghiệp và xem qua một chương trình thực hiện dự kiến ​​ở cấp độ cao. Nếu câu hỏi đưa ra, chúng tôi bước xuống cấp độ thấp hơn. Điều quan trọng là tìm hiểu xem người khác có thể hiểu giải pháp của bạn đủ tốt để duy trì nó hay không.

Cuối cùng, tôi bắt đầu viết mã. Tôi cố gắng giữ nó rất đơn giản đầu tiên. Chỉ là đường dẫn mã, không có gì lạ mắt. Di chuyển càng ít trạng thái càng tốt. Tránh viết. Tránh đọc có thể xung đột với viết. Tránh, trên tất cả, viết có thể xung đột với viết. Rất dễ dàng để thấy rằng bạn có số lượng độc hại tích cực trong số này, và giải pháp đẹp của bạn đột nhiên ít hơn một cách tiếp cận nối tiếp bộ nhớ cache.

Một quy tắc tốt là sử dụng các khung công tác bất cứ khi nào bạn có thể. Nếu bạn đang tự viết các thành phần luồng cơ bản, như các cấu trúc dữ liệu được đồng bộ hóa tốt hoặc các nguyên tắc đồng bộ thực tế, thì bạn gần như chắc chắn sẽ thổi bay toàn bộ chân của bạn.

Cuối cùng là công cụ. Gỡ lỗi là rất khó. Tôi sử dụng valgrind \ callgrind trên linux kết hợp với mã PIN và các studio song song trên windows. Đừng thử và gỡ lỗi những thứ này bằng tay. Bạn có thể có thể. Nhưng có lẽ bạn sẽ ước bạn đã không. Mười giờ thành thạo một số công cụ mạnh mẽ và một số mô hình tốt sẽ giúp bạn tiết kiệm hàng trăm giờ sau đó.

Trên hết, làm việc tăng dần. Làm việc cẩn thận. Không viết mã đồng thời khi mệt mỏi. Đừng viết nó khi đói. Trong thực tế, nếu bạn có thể tránh nó, đơn giản là đừng viết nó. Đồng thời là khó khăn và tôi đã thấy rằng nhiều ứng dụng liệt kê nó là một tính năng thường đi kèm với nó như là tính năng duy nhất của chúng.

Tóm lại:
Bắt đầu:
Think
Talk
Test
Viết đơn giản
Đọc
Kiểm tra
Viết
Gỡ lỗi
GOTO Bắt đầu

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.