Tôi đã phải đối mặt với vấn đề này nhiều lần trong những năm gần đây khi viết mã xử lý luồng cho một số dự án. Tôi đang cung cấp một câu trả lời muộn vì hầu hết các câu trả lời khác, trong khi cung cấp giải pháp thay thế, không thực sự trả lời câu hỏi về kiểm tra. Câu trả lời của tôi được đề cập đến các trường hợp không có sự thay thế cho mã đa luồng; Tôi bao gồm các vấn đề thiết kế mã cho đầy đủ, nhưng cũng thảo luận về thử nghiệm đơn vị.
Viết mã đa luồng có thể kiểm tra
Điều đầu tiên cần làm là tách mã xử lý luồng sản xuất của bạn khỏi tất cả các mã thực hiện xử lý dữ liệu thực tế. Bằng cách đó, việc xử lý dữ liệu có thể được kiểm tra dưới dạng mã đơn luồng và điều duy nhất mà mã đa luồng thực hiện là phối hợp các luồng.
Điều thứ hai cần nhớ là các lỗi trong mã đa luồng là xác suất; các lỗi xuất hiện ít thường xuyên nhất là các lỗi sẽ lén lút vào sản xuất, sẽ khó sinh sản ngay cả trong sản xuất và do đó sẽ gây ra những vấn đề lớn nhất. Vì lý do này, cách tiếp cận mã hóa tiêu chuẩn của việc viết mã nhanh chóng và sau đó gỡ lỗi cho đến khi nó hoạt động là một ý tưởng tồi cho mã đa luồng; nó sẽ dẫn đến mã nơi sửa các lỗi dễ dàng và các lỗi nguy hiểm vẫn còn đó.
Thay vào đó, khi viết mã đa luồng, bạn phải viết mã với thái độ rằng bạn sẽ tránh viết lỗi ngay từ đầu. Nếu bạn đã loại bỏ mã xử lý dữ liệu đúng cách, mã xử lý luồng phải đủ nhỏ - tốt nhất là một vài dòng, tệ nhất là vài chục dòng - rằng bạn có cơ hội viết mã mà không viết lỗi và chắc chắn không viết nhiều lỗi , nếu bạn hiểu luồng, hãy dành thời gian và cẩn thận.
Viết bài kiểm tra đơn vị cho mã đa luồng
Khi mã đa luồng được viết càng cẩn thận càng tốt, vẫn đáng để viết các bài kiểm tra cho mã đó. Mục đích chính của các bài kiểm tra không phải là quá nhiều để kiểm tra các lỗi điều kiện cuộc đua phụ thuộc thời gian cao - không thể kiểm tra lặp lại các điều kiện cuộc đua như vậy - mà là để kiểm tra rằng chiến lược khóa của bạn để ngăn chặn các lỗi đó cho phép nhiều luồng tương tác như dự định .
Để kiểm tra đúng hành vi khóa chính xác, kiểm tra phải bắt đầu nhiều luồng. Để làm cho bài kiểm tra có thể lặp lại, chúng tôi muốn các tương tác giữa các luồng xảy ra theo thứ tự dự đoán. Chúng tôi không muốn đồng bộ hóa bên ngoài các luồng trong thử nghiệm, vì điều đó sẽ che giấu các lỗi có thể xảy ra trong sản xuất khi các luồng không được đồng bộ hóa bên ngoài. Điều đó khiến cho việc sử dụng độ trễ thời gian để đồng bộ hóa luồng, đây là kỹ thuật mà tôi đã sử dụng thành công bất cứ khi nào tôi phải viết các bài kiểm tra mã đa luồng.
Nếu độ trễ quá ngắn, thì thử nghiệm trở nên mong manh, bởi vì sự khác biệt nhỏ về thời gian - nói giữa các máy khác nhau mà thử nghiệm có thể chạy - có thể khiến thời gian bị tắt và thử nghiệm thất bại. Những gì tôi thường làm là bắt đầu với độ trễ gây ra lỗi thử nghiệm, tăng độ trễ để thử nghiệm vượt qua đáng tin cậy trên máy phát triển của tôi và sau đó tăng gấp đôi độ trễ vượt quá để thử nghiệm có cơ hội vượt qua các máy khác. Điều này không có nghĩa là thử nghiệm sẽ mất một lượng thời gian vĩ mô, mặc dù theo kinh nghiệm của tôi, thiết kế thử nghiệm cẩn thận có thể giới hạn thời gian đó không quá một chục giây. Vì bạn không nên có nhiều nơi yêu cầu mã phối hợp luồng trong ứng dụng của mình, điều đó có thể chấp nhận được đối với bộ thử nghiệm của bạn.
Cuối cùng, theo dõi số lượng lỗi bắt gặp trong bài kiểm tra của bạn. Nếu thử nghiệm của bạn có phạm vi bảo hiểm mã 80%, có thể dự kiến sẽ bắt được khoảng 80% lỗi của bạn. Nếu thử nghiệm của bạn được thiết kế tốt nhưng không tìm thấy lỗi, có khả năng hợp lý là bạn không có thêm lỗi sẽ chỉ xuất hiện trong sản xuất. Nếu thử nghiệm bắt được một hoặc hai lỗi, bạn vẫn có thể gặp may. Ngoài ra, và bạn có thể muốn xem xét đánh giá cẩn thận hoặc thậm chí viết lại hoàn toàn mã xử lý luồng của mình, vì có khả năng mã đó vẫn chứa các lỗi ẩn sẽ rất khó tìm thấy cho đến khi mã được sản xuất và rất Khó sửa rồi.