Theo tôi, đây là một câu hỏi phỏng vấn tuyệt vời - ít nhất là giả sử (1) ứng viên dự kiến sẽ có kiến thức sâu về luồng, và (2) người phỏng vấn cũng có kiến thức sâu và đang sử dụng câu hỏi để thăm dò ứng viên. Luôn luôn có khả năng người phỏng vấn đang tìm kiếm một câu trả lời cụ thể, hẹp, nhưng một người phỏng vấn có thẩm quyền nên tìm kiếm những điều sau đây:
- Khả năng phân biệt các khái niệm trừu tượng với thực hiện cụ thể. Tôi ném cái này vào chủ yếu như một bình luận meta về một số ý kiến. Không, không có nghĩa gì khi xử lý một danh sách các từ theo cách này. Tuy nhiên, khái niệm trừu tượng về một đường ống hoạt động, có thể trải rộng trên nhiều máy có khả năng khác nhau, rất quan trọng.
- Theo kinh nghiệm của tôi (gần 30 năm ứng dụng phân tán, đa quy trình và đa luồng), phân phối công việc không phải là phần khó. Thu thập các kết quả và phối hợp các quy trình độc lập là nơi xảy ra hầu hết các lỗi luồng (một lần nữa, theo kinh nghiệm của tôi). Bằng cách chắt lọc vấn đề xuống một chuỗi đơn giản, người phỏng vấn có thể thấy ứng viên nghĩ tốt như thế nào về sự phối hợp. Thêm vào đó, người phỏng vấn có cơ hội hỏi tất cả các loại câu hỏi tiếp theo, chẳng hạn như "OK, nếu mỗi chủ đề phải gửi từ của nó đến một chủ đề khác để tái thiết."
- Ứng viên có nghĩ về cách mô hình bộ nhớ của bộ xử lý có thể ảnh hưởng đến việc thực hiện không? Nếu kết quả của một thao tác không bao giờ bị xóa khỏi bộ đệm L1, thì đó là một lỗi ngay cả khi không có sự tương tranh rõ ràng.
- Có ứng cử viên tách luồng từ logic ứng dụng?
Điểm cuối cùng này, theo tôi, là quan trọng nhất. Một lần nữa, dựa trên kinh nghiệm của tôi, việc gỡ lỗi mã luồng trở nên khó khăn hơn theo cấp số nhân nếu luồng được trộn với logic ứng dụng (chỉ cần xem tất cả các câu hỏi Xoay trên SO chẳng hạn). Tôi tin rằng mã đa luồng tốt nhất được viết dưới dạng mã đơn luồng độc lập, với các chuyển giao được xác định rõ ràng.
Với ý nghĩ này, cách tiếp cận của tôi sẽ là cung cấp cho mỗi luồng hai hàng đợi: một cho đầu vào, một cho đầu ra. Các chuỗi xử lý trong khi đọc hàng đợi đầu vào, loại bỏ từ đầu tiên của chuỗi và chuyển phần còn lại của chuỗi vào hàng đợi đầu ra của nó. Một số tính năng của phương pháp này:
- Mã ứng dụng chịu trách nhiệm đọc hàng đợi, làm gì đó với dữ liệu và viết hàng đợi. Nó không quan tâm liệu nó có đa luồng hay không, hoặc hàng đợi là hàng đợi trong bộ nhớ trên một máy hay hàng đợi dựa trên TCP giữa các máy sống ở hai phía đối diện của thế giới.
- Bởi vì mã ứng dụng được viết dưới dạng đơn luồng, nên nó có thể kiểm tra theo cách xác định mà không cần nhiều giàn giáo.
- Trong giai đoạn thực thi, mã ứng dụng sở hữu chuỗi đang được xử lý. Nó không phải quan tâm đến việc đồng bộ hóa với các luồng thực thi đồng thời.
Điều đó nói rằng, vẫn còn rất nhiều khu vực màu xám mà một người phỏng vấn có thẩm quyền có thể thăm dò:
- "OK, nhưng chúng tôi đang muốn xem kiến thức của bạn về các nguyên thủy đồng thời; bạn có thể thực hiện một hàng đợi chặn không?" Tất nhiên, câu trả lời đầu tiên của bạn là bạn nên sử dụng hàng đợi chặn được xây dựng trước từ nền tảng bạn chọn. Tuy nhiên, nếu bạn hiểu các luồng, bạn có thể tạo một triển khai hàng đợi trong hàng tá dòng mã, sử dụng bất kỳ nguyên tắc đồng bộ hóa nào mà nền tảng của bạn hỗ trợ.
- "Điều gì sẽ xảy ra nếu một bước trong quy trình mất một thời gian rất dài?" Bạn nên suy nghĩ về việc bạn muốn một hàng đợi đầu ra bị ràng buộc hoặc không bị ràng buộc, làm thế nào bạn có thể xử lý lỗi và ảnh hưởng đến thông lượng tổng thể nếu bạn có độ trễ.
- Làm thế nào để hiệu quả enqueue chuỗi nguồn. Không nhất thiết là vấn đề nếu bạn đang xử lý hàng đợi trong bộ nhớ, nhưng có thể là vấn đề nếu bạn di chuyển giữa các máy. Bạn cũng có thể khám phá các trình bao bọc chỉ đọc ở trên một mảng byte bất biến nằm bên dưới.
Cuối cùng, nếu bạn có kinh nghiệm về lập trình đồng thời, bạn có thể nói về một số khung công tác (ví dụ: Akka cho Java / Scala) đã theo mô hình này.