2009-02-03 44 views
28

Trong một cửa sổ đơn tác động gọi Thread.Sleep(1) như minh họa trong đoạn mã sau là gì:Tác động của Thread.Sleep (1) trong C# là gì?

public Constructor() 
{ 
    Thread thread = new Thread(Task); 
    thread.IsBackground = true; 
    thread.Start(); 
} 

private void Task() 
{ 
    while (true) 
    { 
     // do something 
     Thread.Sleep(1); 
    } 
} 

Will chủ đề này heo tất cả các CPU có sẵn?

Tôi có thể sử dụng các kỹ thuật lược tả nào để đo lường mức sử dụng CPU của Chủ đề này (ngoài trình quản lý tác vụ)?

+0

Tất cả các câu trả lời cho đến nay cho thấy hiệu ứng sẽ không đáng kể, nhưng bạn có thể giải thích rõ ràng về những gì bạn đang cố gắng thực hiện với điều này không? – JMD

+0

Tôi chỉ đang cố gắng xem ứng dụng GUI của mình có dành tất cả thời gian trong chuỗi này vì độ trễ 1ms ngắn hay không. –

Trả lời

43

Như đã nêu, vòng lặp của bạn sẽ không hog CPU.

Nhưng hãy cẩn thận: Windows là không một hệ điều hành thời gian thực, vì vậy bạn sẽ không nhận được 1000 đánh thức mỗi giây từ Thread.Sleep (1). Nếu bạn chưa sử dụng timeBeginPeriod để đặt độ phân giải tối thiểu, bạn sẽ đánh thức khoảng 15 ms một lần. Ngay cả sau khi bạn đã đặt độ phân giải tối thiểu thành 1 ms, bạn vẫn sẽ chỉ thức dậy sau mỗi 3-4 ms.

Để có được độ chi tiết của bộ tính giờ milli giây, bạn phải sử dụng bộ hẹn giờ đa phương tiện Win32 (C# wrapper).

+0

Bạn có thể cho ví dụ về thiết lập timeBeginPeriod trong C# không? –

+3

http://www.pinvoke.net/default.aspx/winmm.timeBeginPeriod Theo tài liệu MSDN, timeBeginPeriod phải được kết hợp với một cuộc gọi timeEndPeriod. Cũng lưu ý rằng "Chức năng này ảnh hưởng đến cài đặt Windows chung." và có thể ảnh hưởng đến hiệu năng hệ thống. –

28

Không, nó sẽ không hoán đổi CPU, nó sẽ chỉ tạm dừng chuỗi của bạn cho ít nhất là dài. Trong khi luồng của bạn bị tạm dừng, hệ điều hành có thể lên lịch một luồng không liên quan khác để sử dụng bộ vi xử lý.

+1

Nó sẽ hog rất nhiều thời gian CPU không cần thiết, mặc dù. –

+0

@Joel Làm cách nào/tại sao nó lại tốn nhiều thời gian hơn trong khi (đúng) {i ++; } hoặc về cơ bản là giống nhau về mặt sử dụng CPU? – DevinB

+8

Trên một CPU hiện đại, một giấc ngủ 1ms là một cõi đời đời so với việc thực hiện i ++. – Serguei

2

Không, nó sẽ không hog tất cả CPU có sẵn, bởi vì một chủ đề ngủ sẽ được tắt bởi bộ lập lịch của hệ điều hành khi một luồng khác có tác dụng.

2

Không, nó sẽ không. Bạn sẽ hầu như không nhìn thấy nó. Một nơi nào đó ít hơn 1000 lần một giây chủ đề này sẽ thức dậy và làm gì bên cạnh không có gì trước khi ngủ một lần nữa.

Chỉnh sửa:

Tôi phải kiểm tra. Chạy trên Java 1.5, thử nghiệm này

@Test 
public void testSpeed() throws InterruptedException { 
    long currentTime = System.currentTimeMillis(); 
    int i = 0; 
     while (i < 1000) 
     { 
      Thread.sleep(1); 
      i++; 
     } 
    System.out.println("Executed in " + (System.currentTimeMillis() - currentTime)); 
} 

Chạy ở mức 500 mỗi giây trên máy 3gz của tôi. Tôi cho rằng C# nên khá giống nhau. Tôi cho rằng một người nào đó sẽ báo cáo lại với số C# cho điểm chuẩn quan trọng trong thế giới thực này. Không có sử dụng CPU quan sát được, bằng cách này.

+0

Tôi nghi ngờ nó sẽ xảy ra thậm chí thường xuyên: các đối số để ngủ là một thời gian tối thiểu, và bối cảnh chuyển đổi mất quá nhiều thời gian để có được nhiều trong anyway. –

+0

Trên hệ thống đa lõi hiện đại 1ms là một thời gian dài mạnh. Tôi tự hỏi làm thế nào vòng lặp này thực sự sẽ chạy? – krosenvold

0

Một luồng có thể tối đa một CPU một lần (logic) tại một thời điểm. Và một giấc ngủ 1ms sẽ không được hogging. Đừng đổ mồ hôi.

19

Thread.Sleep (1) như đã nêu sẽ không hog CPU.

Đây là những gì sẽ xảy ra khi một sợi ngủ (nhiều hơn hoặc ít hơn):

  • Thread.Sleep được dịch sang một cuộc gọi hệ thống, do đó gây nên một cái bẫy (sự gián đoạn cho phép hệ điều hành để mất control)
  • Hệ điều hành phát hiện cuộc gọi đến chế độ ngủ và đánh dấu chủ đề của bạn là bị chặn.
  • Nội bộ hệ điều hành giữ một danh sách các chủ đề cần được đánh thức và khi nào điều đó xảy ra.
  • Vì chuỗi không còn sử dụng CPU OS nữa ...
  • Nếu quá trình cha mẹ không sử dụng hết thời gian, hệ điều hành sẽ lên lịch một luồng khác của quy trình để thực thi.
  • Nếu không, một quy trình khác (hoặc quá trình nhàn rỗi) sẽ bắt đầu thực hiện.
  • Khi đến hạn, chuỗi của bạn sẽ được lên lịch lại để thực thi, điều đó không có nghĩa là chuỗi đó sẽ bắt đầu thực hiện tự động.

Lưu ý cuối cùng, tôi không biết chính xác bạn đang làm gì nhưng có vẻ như bạn đang cố gắng đảm nhận vai trò của người lên lịch, ngủ để cung cấp cho CPU thời gian thực hiện điều ...

Trong một vài trường hợp (rất ít thực sự) nó có thể là tất cả các quyền, nhưng chủ yếu là bạn nên để lên lịch làm việc của mình, thì có lẽ biết nhiều hơn bạn làmcó thể làm cho công việc tốt hơn bạn có thể làm điều đó.

4

Như Bob Nadler đã đề cập Thread.Sleep(1) không đảm bảo thời gian ngủ là 1ms.

Dưới đây là ví dụ sử dụng bộ hẹn giờ đa phương tiện Win32 để buộc ngủ 1ms.

[DllImport("winmm.dll")] 
    internal static extern uint timeBeginPeriod(uint period); 
    [DllImport("winmm.dll")] 
    internal static extern uint timeEndPeriod(uint period); 

    timeBeginPeriod(1); 
    while(true) 
    { 
     Thread.Sleep(1); // will sleep 1ms every time 
    } 
    timeEndPeriod(1); 

Kiểm tra điều này trong ứng dụng C# GUI, tôi thấy rằng ứng dụng đã sử dụng khoảng 50% CPU của tôi.

Để thảo luận thêm về chủ đề này thấy các chủ đề diễn đàn sau đây:

http://www.dotnet247.com/247reference/msgs/57/289291.aspx

3

Đây là một chủ đề cũ mà đi lên trong rất nhiều tìm kiếm của tôi, nhưng Win7 có một lịch trình mới và dường như hoạt động khác so với trên.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      DateTime dtEnd = DateTime.Now.AddSeconds(1.0); 
      int i = 0; 
      while (DateTime.Now < dtEnd) 
      { 
       i++; 
       Thread.Sleep(1); 
      } 

      Console.WriteLine(i.ToString()); 

      i = 0; 
      long lStart = DateTime.Now.Ticks; 
      while (i++ < 1000) 
       Thread.Sleep(1); 

      long lTmp = (DateTime.Now.Ticks - lStart)/10000; 

      Console.WriteLine(lTmp.ToString()); 

      Console.Read(); 
     } 
    } 
} 

Với mã trên, kết quả đầu tiên của tôi cho 946. Vì vậy, trong khoảng thời gian 1 giây sử dụng 1ms ngủ, tôi đã nhận 946 lần thức giấc. Đó là rất gần với 1ms.

Phần thứ hai yêu cầu phải mất bao lâu để thực hiện 1000 sự kiện ngủ ở mức 1ms mỗi sự kiện. Tôi có 1034ms. Một lần nữa, gần 1ms.

Đây là trên Core2Duo 1.8GHz + Win7 sử dụng Net 4.0

Edit: nhớ, giấc ngủ (x) không có nghĩa là thức dậy lên vào thời điểm này, nó có nghĩa là đánh thức tôi dậy không sớm hơn thời gian này . Nó không được bảo đảm. Mặc dù, bạn có thể tăng mức độ ưu tiên của chuỗi và Windows sẽ lên lịch chuỗi của bạn trước các chuỗi ưu tiên thấp hơn.

+1

Nhận xét để thêm về trình lập lịch biểu Win 7. Tôi đã chạy ví dụ "không gian tên ConsoleApplication2" của Bengie và nó báo cáo 65 và 15600 chỉ ra khoảng ~ 15ms bước. Đây là một 3.33Mhx kép chạy. NET 3.5, Win 7. Điều kỳ lạ là ngày hôm qua tôi có các bản ghi với một số mã đã được trưng bày giấc ngủ (1) gần hơn đến 1ms như bài viết của mình tuyên bố. Kết luận của tôi là có một số thiết lập hoặc cấu hình đã thay đổi trên máy tính của tôi nhưng tôi không thể xác định. Cùng một câu trả lời trong chế độ gỡ lỗi hoặc phát hành có hoặc không có trình gỡ lỗi. Tôi không sử dụng TimePeriod bắt đầu/kết thúc. Có rất ít tải trên ma – crokusek

0

cũng có một cái nhìn lúc này: msdn forum

using System; 
using System.Diagnostics; 
using System.Runtime.InteropServices; 
using System.Threading; 

namespace Test 
{ 
    public static class Program 
    { 
     public static void Main(string[] args) 
     { 
      Stopwatch sw = new Stopwatch(); 

      for (int i = 0; i < 10; ++i) 
      { 
       sw.Reset(); 
       sw.Start(); 
       Thread.Sleep(50); 
       sw.Stop(); 

       Console.WriteLine("(default) Slept for " + sw.ElapsedMilliseconds); 

       TimeBeginPeriod(1); 
       sw.Reset(); 
       sw.Start(); 
       Thread.Sleep(50); 
       sw.Stop(); 
       TimeEndPeriod(1); 

       Console.WriteLine("(highres) Slept for " + sw.ElapsedMilliseconds + "\n"); 
      } 
     } 

     [DllImport("winmm.dll", EntryPoint="timeBeginPeriod", SetLastError=true)] 
     private static extern uint TimeBeginPeriod(uint uMilliseconds); 

     [DllImport("winmm.dll", EntryPoint="timeEndPeriod", SetLastError=true)] 
     private static extern uint TimeEndPeriod(uint uMilliseconds); 
    } 
} 
4

lần ngủ nhỏ nên tránh như một sợi bỏ lát thời gian của nó được một sự thúc đẩy ưu tiên khi resignaled, và có thể dẫn đến tắc bối cảnh cao. Trong một ứng dụng multithreaded/server, điều này có thể dẫn đến một hiệu ứng thrashing khi các chủ đề đang chiến đấu cho thời gian CPU. Thay vào đó, hãy dựa vào các hàm không đồng bộ và các đối tượng đồng bộ hóa như các phần quan trọng hoặc các mutex/semaphores.

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