2009-02-03 3 views
28

В окне формы приложения, что это влияние вызова Thread.Sleep(1), как показано в следующем коде:Какое влияние Thread.Sleep (1) на C#?

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

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

Будет ли эта нить боры всех доступных ресурсов процессора?

Какие методы профилирования я могу использовать для измерения использования ЦП этой нити (кроме диспетчера задач)?

+0

Все ответы до сих пор указывают на то, что эффект будет незначительным, но можете ли вы дать некоторое разъяснение о том, что вы пытаетесь сделать с этим? – JMD

+0

Я просто пытаюсь проверить, работает ли мое приложение GUI в течение всего этого времени из-за короткой задержки 1 мс. –

ответ

43

Как уже говорилось, ваша петля не будет запускать процессор.

Но остерегайтесь: Windows является не реального времени OS, так что вы будете не получить 1000 поминки в секунду от Thread.Sleep (1). Если вы не использовали timeBeginPeriod, чтобы установить минимальное разрешение, вы просыпаетесь каждые 15 мс. Даже после того, как вы установили минимальное разрешение на 1 мс, вы все равно будете просыпаться каждые 3-4 мс.

Чтобы получить гранулярность таймера уровня миллисекунды, вы должны использовать мультимедийный таймер Win32 (C# wrapper).

+0

Не могли бы вы привести пример настройки timeBeginPeriod в C#? –

+3

http://www.pinvoke.net/default.aspx/winmm.timeBeginPeriod В соответствии с документом MSDN timeBeginPeriod следует сопоставлять вызовом timeEndPeriod. Также обратите внимание: «Эта функция влияет на глобальную настройку Windows». и может повлиять на производительность системы. –

28

Нет, он не будет болеть за процессор, он просто остановит вашу нить для как минимум, что долго. Пока ваш поток приостановлен, операционная система может запланировать другой, несвязанный поток, чтобы использовать процессор.

+1

Было бы излишним много времени процессора без необходимости. –

+0

@Joel How/why be hog больше времени, чем while (true) {i ++; } или это по существу то же самое с точки зрения использования ЦП? – DevinB

+8

На современном процессоре 1 мс сон - это вечность по сравнению с i ++. – Serguei

2

Нет, он не будет обрабатывать весь доступный CPU, поскольку спящий поток будет отключен планировщиком ОС, когда другой поток будет работать.

2

Нет, не будет. Вы это почти не увидите. Где-то менее 1000 раз в секунду этот поток проснется и почти ничего не сделает, прежде чем снова спать.

Редактировать:

Я должен был проверить. Запуск на Java 1.5, этот тест

@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)); 
} 

Ранг при скорости около 500 спящих в секунду на моей машине 3ghz. Я полагаю, что C# должен быть примерно таким же. Я предполагаю, что кто-то отчитается с номерами C# для этого чрезвычайно важного эталона. Между прочим, никакого наблюдаемого использования ЦП не наблюдалось.

+0

Я сомневаюсь, что это произойдет даже так часто: аргумент для сна - это минимальное время, и переключение контекста занимает слишком много времени, чтобы получить много в любом случае. –

+0

На современных многоядерных системах 1 мс - очень долгое время. Интересно, как будет работать этот цикл? – krosenvold

0

Нить может не более одного (логического) процессора за раз. И сон на 1 мс не будет болеть. Не потейте.

19

Thread.Sleep (1), как указано, не запустит процессор.

Вот что происходит, когда поток спит (более или менее):

  • Thread.Sleep переводится в системный вызов, который, в свою очередь, вызывает ловушку (прерывание, что позволяет операционной системе принимать управление)
  • Операционная система обнаруживает вызов в режиме сна и отмечает вашу нить как заблокированную.
  • Внутренне ОС хранит список потоков, которые необходимо пробудить и когда это произойдет.
  • Поскольку поток больше не использует процессор ОС ...
  • Если родительский процесс не исчерпал весь свой временной срез, ОС будет планировать другой поток процесса для выполнения.
  • В противном случае начнется выполнение другого процесса (или незанятого процесса).
  • Когда время наступит, ваш поток будет запланирован еще раз для выполнения, что не означает, что он начнет выполнение автоматически.

В заключение я не знаю точно, что вы делаете, но, похоже, вы пытаетесь взять на себя роль планировщика, то есть спать, чтобы предоставить процессору время для других вещи ...

В некоторых случаях (очень немногие действительно) это может быть все в порядке, но в основном вы должны позволить планировщик делать свою работу, он, вероятно, знает больше, чем вы и может сделать работу лучше, чем вы можете это сделать.

4

Как отметил Боб Надлер, Thread.Sleep(1) не гарантирует время сна 1 мс.

Вот пример использования мультимедийного таймера Win32, чтобы заставить спать 1 мс.

[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); 

Тестирование это в C# GUI приложения, я обнаружил, что приложение используется около 50% моего процессора.

Для более подробного обсуждения по этой теме в следующей теме на форуме:

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

3

Это старая нить, которая приходит в много моих поисков, но Win7 имеет новый планировщик и, кажется, ведут себя иначе, чем выше.

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(); 
     } 
    } 
} 

С выше кода, Мой первый результат дал 946. Таким образом, в отрезок времени 1 с использованием второго 1 мс снам, я получил 946 пробуждения взлетов. Это очень близко к 1 мс.

Вторая часть спрашивает, сколько времени требуется, чтобы выполнить 1000 событий сна в 1 мс каждый. Я получил 1034 мс. Опять же, почти 1 мс.

Это было на 1.8GHz Core2Duo + Win7 с .NET 4.0

Edit: помните, что сон (х) не означает, что просыпаться в это время, это не означает, что меня будить не ранее, чем на этот раз , Это не гарантировано. Хотя, вы можете увеличить приоритет потока, и Windows должна запланировать ваш поток до потоков с более низким приоритетом.

+1

Комментарий для добавления планировщика Win 7. Я запустил пример Bengie «namespace ConsoleApplication2», и он сообщил, что 65 и 15600 указывает на примерно 15 мс шагов. Это двойная 3.33Mhx, работающая с .NET 3.5, Win 7. Странно, что вчера у меня есть журналы с кодом, который показывал сон (1) намного ближе к 1 мс, как и его сообщения. Мое заключение заключается в том, что некоторые настройки или конфигурации изменились на моей машине, но я не могу определить. Тот же ответ в режимах отладки или выпуска с отладчиком или без него. Я не использовал начало/конец TimePeriod. На маке очень мало нагрузки – crokusek

0

также посмотреть на это: 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

Малые времена сна следует избегать как нить отказаться от своего квант времени получает повышение приоритета, когда resignaled, и это может привести к высоким переключений контекста. В многопоточном/серверном приложении это может привести к эффекту «трещин», поскольку потоки сражаются за процессорное время. Вместо этого полагайтесь на асинхронные функции и объекты синхронизации, такие как критические разделы или мьютексы/семафоры.

Смежные вопросы