Какое влияние Thread.Sleep (1) в C #? - PullRequest
29 голосов
/ 03 февраля 2009

В приложении Windows Form каков результат вызова Thread.Sleep(1), как показано в следующем коде:

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

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

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

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

Ответы [ 10 ]

43 голосов
/ 03 февраля 2009

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

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

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

28 голосов
/ 03 февраля 2009

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

19 голосов
/ 04 февраля 2009

Thread.Sleep (1), как указано, не будет загружать процессор.

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

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

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

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

4 голосов
/ 03 апреля 2012

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

4 голосов
/ 07 февраля 2009

Как отметил Боб Надлер 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 голосов
/ 02 ноября 2010

Это старый поток, который встречается во многих моих поисках, но в 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,8 ГГц core2duo + Win7 с использованием .Net 4.0

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

2 голосов
/ 03 февраля 2009

Нет, не будет. Ты едва увидишь это. Где-то менее 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 снов в секунду на моей 3 ГГц машине. Я полагаю, что C # должен быть примерно таким же. Я предполагаю, что кто-то сообщит с номерами C # для этого чрезвычайно важного реального эталонного теста. Между прочим, не было заметного использования процессора.

2 голосов
/ 03 февраля 2009

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

0 голосов
/ 21 марта 2011

также посмотрите на это: 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);
    }
}
0 голосов
/ 04 февраля 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...