2009-08-20 67 views
15

Tôi đã đi qua một bài kiểm tra đơn vị đó là không liên tục vì thời gian trôi qua không phải là những gì tôi mong đợi nó được.Chính xác Thread.Sleep (TimeSpan) như thế nào?

Một ví dụ về những gì thử nghiệm điều này có vẻ như là:

Stopwatch stopwatch = new Stopwatch(); 
stopwatch.Start(); 

TimeSpan oneSecond = new TimeSpan(0, 0, 1); 

for(int i=0; i<3; i++) 
{ 
    Thread.Sleep(oneSecond); 
} 

stopwatch.Stop(); 

Assert.GreaterOrEqual(stopwatch.ElapsedMilliseconds, 2999); 

Phần lớn thời gian này trôi qua nhưng nó đã không thành công trên ít nhất là trên một lần thất bại vì:

dự kiến: lớn hơn hoặc bằng đến 2999 Nhưng là: 2998

Tôi không hiểu cách nó có thể nhỏ hơn 3 giây. Có vấn đề về độ chính xác với Thread.Sleep hoặc có thể Đồng hồ bấm giờ mà tôi không biết?

Cũng giống như bản cập nhật cho một số câu hỏi bên dưới. Kịch bản đang được kiểm thử đơn vị là một lớp cho phép người ta gọi một phương thức để thực hiện một số hành động và nếu nó không đợi một giây và nhớ lại phương thức đó. Các thử nghiệm được hiển thị ở trên chỉ là một xấp xỉ của những gì đang xảy ra.

Giả sử tôi muốn gọi phương thức DoSomething() ... nhưng trong trường hợp ngoại lệ bị DoSomething ném() tôi muốn có thể thử gọi lại tối đa 3 lần nhưng đợi 1 giây giữa mỗi lần thử. Mục đích của thử nghiệm đơn vị, trong trường hợp này, là để xác minh rằng khi chúng tôi yêu cầu 3 lần thử lại với 1 giây chờ giữa mỗi lần thử lại, tổng thời gian thực hiện lớn hơn 3 giây.

+0

Chỉ vì tò mò, tại sao bạn có bài kiểm tra đơn vị kiểm tra Thread.Sleep() theo cách này? Tôi đoán rằng bạn đang thực sự thử nghiệm để xem liệu một số hoạt động khác hoàn thành trong chưa đầy 3 giây, nhưng tại sao không chỉ gọi Thread.Sleep (3000)? – MusiGenesis

+0

@MusiGenesis Tôi đã cập nhật câu hỏi để cố gắng làm rõ mọi thứ một chút. – mezoid

+0

Chỉ để biết thông tin. Kể từ khi tôi phát hiện ra mã nhỏ này, tôi sử dụng nó ở mọi nơi: http://www.codeproject.com/KB/cs/highperformancetimercshar.aspx – sabiland

Trả lời

16

Chuỗi của bạn đang chia sẻ CPU Thời gian với các chủ đề khác. Giấc ngủ sẽ kết thúc ngay sau khi đến lượt bạn và hạt nhân thông báo thời gian ngủ đã trôi qua, vì vậy nó không chính xác.

Tải CPU, ưu tiên quy trình, số lượng chuỗi đồng thời, ngay cả từ các quy trình khác, sẽ có tác dụng lên nó.

+4

nhưng nếu nó chỉ kết thúc ngay sau khi hạt nhân thông báo thời gian ngủ đã trôi qua, làm thế nào là nó có thể cho nó để mất ít thời gian hơn tôi mong đợi? 3010ms là dễ hiểu và chấp nhận được trong trường hợp của tôi nó dừng trước khi đạt đến thời gian yêu cầu ... mặc dù bằng 1-2ms – mezoid

+2

Việc triển khai có thể đặt thời gian đánh thức một vài phần nghìn giây trước thời gian bạn chỉ định. Nếu nó không * sẽ luôn luôn * thức dậy sau đó. Bằng cách thiết lập thời gian trước đó, nó có tỷ lệ cược tốt hơn để đến một nơi gần gũi. –

+0

@mezoid: Tôi không nghĩ rằng kiến ​​trúc PC được tạo ra để có độ chính xác về thời gian. Các máy tính cũ "bọ ve" chỉ 18,2 lần mỗi giây, vì vậy đồng hồ và "số đếm" được sử dụng chỉ được cập nhật mỗi 52ms. Tôi tin rằng nó phải nhanh hơn nhiều, nhưng tôi vẫn không chắc nó chính xác như thế nào. – Havenard

8

Thread.Sleep không có ý định được sử dụng để đánh thức chính xác. Thực sự, bản thân kiến ​​trúc cửa sổ không dành cho loại điều này.

1

Trong một ứng dụng mà tôi muốn ngủ ít nhất mili giây x, tôi đã sử dụng một số mã tương tự như:

public void Sleep(int milliseconds) 
{ 
    Stopwatch stopwatch = new Stopwatch(); 
    stopwatch.Start(); 

    while (stopwatch.ElapsedMilliseconds < milliseconds) 
    { 
     int timeout = milliseconds - stopwatch.ElapsedMilliseconds; 
     Thread.Sleep(timeout >= 0 ? timeout : 0); 
    } 

    stopwatch.Stop(); 
} 

Để đối phó với cách Thread.Sleep chính xác là, nó không phải là chính xác cả. Tôi nghĩ độ phân giải là khoảng 10ms. Nó không được đảm bảo để làm được gì nhiều ngoại trừ 'khoảng' dài này.

+0

Tại sao không chỉ Thread.Sleep (mili giây + 100)? – MusiGenesis

+0

Bạn có bất kỳ tham chiếu nào bạn có thể chỉ cho tôi về độ phân giải không? Nếu nó chắc chắn 10ms tôi có thể thay đổi 2999 đến 2990 ..... – mezoid

+1

Không có độ phân giải cứng và nhanh chóng vì những thứ người khác đã lưu ý (chẳng hạn như tải bộ vi xử lý ảnh hưởng đến nó). Về cơ bản nó đi xuống đến bất cứ khi nào thread của bạn được ưu tiên một lần nữa để bắt đầu thực hiện. Bằng chứng giai thoại tôi đã nhìn thấy xung quanh SO ở một số nơi mặc dù đã chỉ đến trung bình khoảng 10ms. –

2

Chủ đề ngủ và thời gian/điều chỉnh là những điều rất khác nhau và cần được xử lý phù hợp. Ngủ một thread là một nhiệm vụ chung, cho phép hệ thống cung cấp cho các luồng khác và xử lý cơ hội để thực thi mà không cần phải cụ thể về nó. Mặt khác, điều chỉnh một ứng dụng hoặc các nhiệm vụ lập lịch biểu cần thời gian chính xác phải được thực hiện với một bộ đếm thời gian rõ ràng.

Hãy nhớ, nếu bạn cần quy trình hoặc đồng bộ hóa chính xác thời gian, bạn sẽ gặp khó khăn trong việc đạt được điều đó với quy trình bình thường trong cửa sổ. Bạn sẽ cần phải sử dụng các ưu tiên thời gian thực của windows để đạt được thành công thời gian hoặc điều chỉnh chính xác, vì các cửa sổ có thể ngủ bất kỳ luồng nào vào bất kỳ lúc nào nếu nó bị chặn bởi một chuỗi khác.

+0

Tôi đồng ý, ý định cho Thread.Sleep là về ưu tiên luồng và không làm với thời gian đồng hồ chính xác. Cho đến khi chúng tôi có thể có đồng hồ xử lý Cesium trong máy tính của chúng tôi, rất tiếc thời gian chính xác (tuyệt đối) sẽ không có sẵn. : P http://en.wikipedia.org/wiki/Caesium – Russell

+0

Vâng, tôi hy vọng hầu hết mọi người không cần thời gian chính xác nguyên tử-đồng hồ. : P Tôi nghĩ rằng đồng hồ trong hầu hết CPU là đủ chính xác cho phần lớn các ứng dụng ngoài việc đo lường các rung động nguyên tử. : D – jrista

2

nhanh chóng thử nghiệm, tôi nhận thấy rằng một đoạn mã như ...

làm {Debug.WriteLine (DateTime.Now.TimeOfDay.TotalMilliseconds.ToString()); } trong khi (1);

hiển thị cùng một số nhiều lần, sau đó nhảy đến một số điện thoại mới hiển thị nhiều lần, vv Khoảng cách giữa các bộ số là luôn 15.625ms mà tôi nhận thấy là 1000/64.

Hình như giờ của Windows có mức độ chi tiết là 1/64 giây. Nếu bạn cần tốt hơn thế thì tôi cảm thấy nỗi đau của bạn, nhưng đó là khuôn khổ bạn phải phù hợp. (Windows không phải là một hệ điều hành thời gian thực cứng và không tuyên bố là).

0

Có thể bạn không nên dựa vào xu hướng thời gian để tìm hiểu xem bạn có thành công hay không. Tốt hơn hãy đếm số lần thử của bạn và đánh giá điều này:

int tries; 

for(tries=0; tries<3; tries++) 
{ 
    Thread.Sleep(oneSecond); 
} 

Assert.GreaterOrEqual(tries, 3); 
Các vấn đề liên quan