2010-07-07 36 views
5

thể trùng lặp:
System.Random keeps on returning the same valueC# Random.Next đột nhiên ngừng trở về giá trị ngẫu nhiên

Tôi refactoring và mở rộng một C# mô hình đại lý dựa trên nhỏ để giúp một số giáo sư sinh học dự đoán lây lan của bệnh. Mỗi năm mô phỏng mỗi tác nhân cá nhân ngẫu nhiên đi đến một nút dân số gần đó, có thể lây lan bệnh. Tôi là thương hiệu mới để C#, nhưng tôi đã đọc về các vấn đề tiềm năng với Random.Next trả về cùng một giá trị nếu tái khởi tạo với cùng một thời gian hệ thống. Để tránh điều này, tôi đã tạo một cá thể tĩnh được tham chiếu cho mỗi giá trị ngẫu nhiên mới.

Các chi tiết cụ thể:

Trong những nỗ lực của tôi để mở rộng quy mô các mô hình tôi đã thay đổi nó để tính toán "du lịch" thông tin cho mỗi nút dân song song. Khi thử nghiệm mô hình, tôi nhận thấy rằng trong phiên bản mới bệnh sẽ không lây lan trong năm đầu tiên. Điều tra thêm thu hẹp vấn đề xuống để di chuyển giữa các nút. Sau năm đầu tiên tất cả các đại lý vẫn bất động. Tôi đã kiểm tra chức năng chịu trách nhiệm cho chuyến đi của họ và thấy rằng nó hoạt động bằng cách tạo danh sách tất cả các nút lân cận, tạo một số ngẫu nhiên < = số lượng phần tử trong danh sách và đi đến listOfNearbyNodes [myRandomNumber].

Vấn đề:

Sau đó tôi thêm tuyên bố in để xuất giá trị của chỉ mục ngẫu nhiên cho mỗi lần lặp. Tôi thấy rằng toàn bộ mô hình hoạt động chính xác như mong đợi cho năm đầu tiên của mô phỏng, với các số ngẫu nhiên được tạo ra trong một phạm vi có thể chấp nhận được. Tuy nhiên, sau năm đầu tiên kết thúc và vòng lặp mô phỏng chính xác cùng một mã sẽ chỉ trả về chỉ số "ngẫu nhiên" 0. Mỗi luồng, mỗi lần lặp, mọi nút, mọi tác nhân, luôn luôn 0. Vì nút hiện tại của tác nhân luôn là mục đầu tiên trong danh sách các đại lý không bao giờ di chuyển một lần nữa. Tôi nghĩ đây có thể là một biểu hiện khác của lỗi hạt thời gian hệ thống, vì vậy tôi đã thử ba cách khác nhau để triển khai một đối tượng ngẫu nhiên tĩnh, nhưng nó không giúp ích gì. Mỗi khi tôi chạy mô phỏng năm đầu tiên luôn hoạt động chính xác và sau đó Random.Next() bắt đầu chỉ trả về 0.

Có ai có ý tưởng về nơi tôi nên xem tiếp theo cho lỗi không? Cảm ơn!

+2

Mẫu mã ngắn nhưng đầy đủ, việc tái tạo lỗi sẽ hữu ích cho cả bạn và cộng đồng SO trong việc giúp bạn chẩn đoán sự cố. – LBushkin

+0

Tôi hỏi một câu hỏi mà tôi nghĩ là có liên quan và có thể giúp: http://stackoverflow.com/questions/2924599/parallel-loops-and-random-produce-odd-results – Mathias

+0

Bản sao của [System.Random tiếp tục trả về cùng một giá trị] (http://stackoverflow.com/questions/295900/system-random-keeps-on-returning-the-same-value). –

Trả lời

18

Tôi nghi ngờ bạn đang sử dụng cùng một phiên bản Random đồng thời trong nhiều chuỗi. Đừng làm điều đó - nó không an toàn.

Options:

  • Tạo một thể hiện mới của Random mỗi thread (ThreadStatic có thể giúp đây)
  • Sử dụng một trường hợp duy nhất của Random, nhưng chỉ từng sử dụng nó trong một khóa.

Tôi có một số blog post với một số mã mẫu, nhưng vui lòng đọc các nhận xét cũng như có những gợi ý tốt để cải thiện nó. Tôi đang lên kế hoạch viết một bài báo khác về ngẫu nhiên tại một thời điểm nào đó trong tương lai gần ...

+0

Cảm ơn, đây chính xác là những gì tôi cần! – Mandelbrot

5

Tôi không tin rằng lớp Random được thiết kế để được an toàn thread (đồng thời có thể sử dụng từ nhiều luồng) - vì vậy nếu bạn đang chia sẻ một cá thể theo cách này, bạn có thể làm hỏng trạng thái của trình tạo ngẫu nhiên, ngăn nó hoạt động chính xác.

Bạn có thể trang trí các biến tĩnh chứa tham chiếu đến lớp ngẫu nhiên như ThreadStatic, mà sẽ cho phép bạn duy trì một trường hợp riêng biệt cho mỗi thread:

[ThreadStatic] 
private static Random m_Random; // don't attempt to initialize this here... 

public void YourThreadStartMethod() 
{ 
    // initialize each random instance as each thread starts... 
    m_Random = new Random(); 
} 

Nếu bạn đang sử dụng .NET 4.0, có cũng là lớp ThreadLocal<T>, giúp tạo ra một thể hiện cho mỗi luồng dễ dàng hơn.

2

Đối tượng Random không phải là thread an toàn. Để khắc phục điều đó, bạn có thể sử dụng mã này bị đánh cắp từ this answer:

class ThreadSafeRandom 
{ 
    private static Random random = new Random(); 

    public static int Next() 
    { 
     lock (random) 
     { 
      return random.Next(); 
     } 
    } 
} 

Bạn cũng có thể sử dụng RNGCryptoServiceProvider, đó là chủ đề an toàn và cũng sản xuất dữ liệu tốt hơn ngẫu nhiên.

Các vấn đề liên quan