2013-09-28 199 views
8

Tôi đã tìm kiếm câu hỏi này nhưng không thấy câu trả lời. Nếu nó là một bản sao tôi sẽ sẵn sàng đóng nó lại.Thread.Sleep (1) mất nhiều hơn 1ms

Tôi hiện đang cố gắng thực hiện một số đánh giá hiệu suất về công nghệ và thấy một số kết quả không thể tin được vì vậy tôi đã quyết định thử nghiệm một số. Trong đó tôi muốn thử xem liệu lớp Đồng hồ bấm giờ có trả lại những gì tôi mong đợi không.

Stopwatch sw = Stopwatch.StartNew(); 
Thread.Sleep(1); 
sw.Stop(); 
Console.WriteLine(sw.ElapsedMilliseconds); 

Trong trường hợp này, tôi thấy khá nhiều giá trị trả về là 15ms. Tôi hiểu độ phân giải của DateTime để được xung quanh có nhưng không nên Thread.Sleep (1) ngủ một sợi cho 1ms? Hệ thống tôi đang trả về Stopwatch.IsHighResolution đúng và hoạt động của nó trong .NET 4.

Bối cảnh: Biểu mẫu đầy đủ và phù hợp này nhằm thu thập một số số trên yêu cầu nhận được Aerospike db. DB không nằm trên cùng một hộp. Khi tôi in ra các sw.ElapsedMilliseconds khi một truy vấn ở giữa tôi nhìn thấy hầu hết các phản ứng phụ millisecond và có vẻ nghi ngờ một chút xem xét mã Java tương đương của tôi là trở lại nhiều hơn đáng tin cậy 5ms-15ms phản ứng hầu hết thời gian. Mã Java đang sử dụng sự khác biệt của System.nanoTime(). Bởi phản ứng submilli trong mã C# của tôi, tôi có nghĩa là Console.WriteLine (sw.ElapsedMilliseconds) in 0.

+0

Tôi nghĩ rằng với số tiền rất thấp, nó sẽ mất nhiều cảm ơn thời gian thực tế cho một sợi đi ngủ và thức dậy một lần nữa. Tôi đề nghị bạn thử và tăng đối số 'sleep()' và xem số đối số và thời gian ngủ thực tế sẽ bằng nhau. – Mehraban

+0

Tôi đã tăng dần lên đến khoảng 100 và tôi vẫn liên tục thấy cao hơn từ 5 đến 15 mili giây. Tôi hiểu nó không phải là một hệ điều hành thời gian thực nhưng tôi không mong đợi để thấy điều này – Rig

+0

Tôi sẽ không nói nó nhất thiết phải là một bản sao nhưng câu trả lời là có. Tôi có nên xóa câu hỏi này không? – Rig

Trả lời

27

Bộ hẹn giờ khác hơn Đồng hồ bấm giờ được tăng thêm bởi ngắt đồng hồ. Mà theo mặc định ticks 64 lần mỗi giây trên Windows. Hoặc 15.625 mili giây. Vì vậy, một đối số Thread.Sleep() nhỏ hơn 16 không cung cấp cho bạn sự chậm trễ mà bạn đang tìm kiếm, bạn sẽ luôn nhận được ít nhất khoảng 15.625 đó. Tương tự, nếu bạn đọc, ví dụ: Environment.TickCount hoặc DateTime.Now và đợi ít hơn hơn 16 mili giây thì bạn sẽ đọc lại cùng một giá trị và nghĩ rằng 0 msec đã trôi qua.

Luôn sử dụng Đồng hồ bấm giờ để đo số gia tăng nhỏ, nó sử dụng nguồn tần số khác. Độ phân giải của nó thay đổi, nó phụ thuộc vào chipset trên bo mạch chủ. Nhưng bạn có thể dựa vào nó tốt hơn một micro giây. Stopwatch.Frequency cung cấp cho bạn tốc độ.

Tốc độ ngắt đồng hồ có thể được thay đổi, bạn phải ghim timeBeginPeriod(). Điều đó có thể giúp bạn giảm xuống một phần nghìn giây và thực sự làm cho Thread.Sleep (1) chính xác. Tốt nhất không làm điều này, nó là rất sức mạnh không thân thiện.

+0

Vâng, luôn có bộ hẹn giờ đa phương tiện –

+0

Đối với những người khác đến chủ đề này, tôi đã thử nghiệm để xác minh với Mono C# dưới linux/ubuntu bằng cách sử dụng Thread.Sleep (1) ngủ thread cho chính xác 1ms. – JaredBroad

+2

@JaredBroad - tất nhiên, vấn đề là Windows cụ thể. (Và câu trả lời cung cấp cho bạn một đầu mối về cách "sửa" hành vi trong cửa sổ - nhưng một lần nữa, sức mạnh của nó đói, vì vậy, đối với hầu hết các kịch bản, không đáng giá.) – BrainSlugs83

0

Thread.Sleep (n) có nghĩa là chặn luồng hiện tại cho ít nhất số lần timelices (hoặc số lượng luồng) có thể xảy ra trong vòng mili giây. Độ dài của một timeslice là khác nhau trên các phiên bản khác nhau/các loại Windows và bộ xử lý khác nhau và thường khoảng từ 15 đến 30 mili giây. Điều này có nghĩa là chủ đề gần như được đảm bảo để chặn hơn n mili giây. Khả năng chủ đề của bạn sẽ được đánh thức lại chính xác sau khi n mili giây là không thể thực hiện được. Vì vậy, Thread.Sleep là vô nghĩa cho thời gian.

+0

Tôi đã không thực sự sử dụng Thread.Sleep cho thời gian mà là để xác nhận thời gian phản ứng cực nhanh của tôi, khi nó quay ra, dường như là chính xác. Tôi chắc chắn hiểu điểm của bạn mặc dù. – Rig

0

Thread.Sleep(1) sẽ đặt một chủ đề để ngủ trong 1ms, nhưng bạn thường không thể có được độ chính xác đó.

Tuy nhiên, khi chuỗi đi vào trạng thái ngủ, cần có thời gian để hạt nhân đưa nó trở lại hàng đợi sẵn sàng và sau đó đặt nó vào trạng thái hoạt động khi chuỗi thực sự sẽ chạy lại.

Tất cả các yếu tố này phụ thuộc vào nền tảng, số lượng CPU, số lượng các quy trình khác, v.v. Với hệ điều hành không phải RT, bạn không thể đảm bảo về điều này.

+0

Thiết bị dựa trên RT có cung cấp hợp đồng khác ở đây không? Điều này có liên quan vì tôi đang làm việc trên một ứng dụng tương thích RT riêng biệt. – Rig

1

Có những gì bạn đã tìm ra là hoàn toàn chính xác.

Thread.Sleep không đảm bảo phát hành ở N mili giây. Nó sẽ đảm bảo rằng Sleep sẽ không phát hành trước N mili giây.

Nói cách khác Thread.Sleep(1) có nghĩa là Giấc ngủ trong ít nhất 1 mili giây. Hệ điều hành sẽ không lập lịch trình lát thời gian cho một chuỗi cụ thể cho một lượng thời gian cụ thể.

Chủ đề sẽ không được hệ thống điều hành thực hiện trong khoảng thời gian được chỉ định. Phương pháp này thay đổi trạng thái của luồng để bao gồm WaitSleepJoin.

Từ Msdn

5

Tôi hy vọng rằng Thread.Sleep là gì khác hơn là một wrapper quản lý xung quanh Win32 API Sleep. Người ta biết rằng hàm API này có độ phân giải thấp.Tài liệu nói điều này:

Hàm này làm cho một chuỗi từ bỏ phần còn lại của lát thời gian và không thể khởi động trong một khoảng thời gian dựa trên giá trị của dwMilli giây. Đồng hồ hệ thống "tick" với tốc độ không đổi. Nếu dwMilliseconds nhỏ hơn độ phân giải của đồng hồ hệ thống, luồng có thể ngủ ít hơn khoảng thời gian đã chỉ định. Nếu dwMilliseconds lớn hơn một đánh dấu nhưng nhỏ hơn hai, thì sự chờ đợi có thể ở bất kỳ đâu giữa một và hai dấu tích, v.v. Để tăng độ chính xác của khoảng thời gian ngủ, hãy gọi hàm timeGetDevCaps để xác định độ phân giải hẹn giờ tối thiểu được hỗ trợ và chức năng timeBeginPeriod để đặt độ phân giải bộ hẹn giờ ở mức tối thiểu. Hãy thận trọng khi gọi timeBeginPeriod, vì các cuộc gọi thường xuyên có thể ảnh hưởng đáng kể đến đồng hồ hệ thống, mức sử dụng nguồn hệ thống và trình lên lịch. Nếu bạn gọi timeBeginPeriod, hãy gọi nó sớm một lần trong ứng dụng và chắc chắn gọi hàm timeEndPeriod ở cuối ứng dụng.

Sau khi khoảng thời gian ngủ trôi qua, chuỗi đã sẵn sàng để chạy. Nếu bạn chỉ định 0 mili giây, chuỗi sẽ từ bỏ phần còn lại của lát thời gian của nó nhưng vẫn sẵn sàng. Lưu ý rằng một chuỗi sẵn sàng không được đảm bảo để chạy ngay lập tức. Do đó, luồng có thể không chạy cho đến một thời gian sau khi khoảng thời gian ngủ trôi qua. Để biết thêm thông tin, hãy xem Ưu tiên lập lịch biểu.

Vì vậy, bạn có thể sử dụng timeBeginPeriodtimeEndPeriod làm đề xuất để tăng độ phân giải hẹn giờ, nhưng điều đó thực sự không được khuyến khích. Nếu bạn thực sự cần chặn trong một khoảng thời gian ngắn thì tôi khuyên bạn nên tìm một giải pháp tốt hơn. Ví dụ: bộ hẹn giờ đa phương tiện.