Каково влияние Thread.Sleep(1) на С#?
В приложении формы Windows какое влияние вызывает вызов 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);
}
}
Будет ли этот поток запугать весь доступный CPU?
Какие методы профилирования я могу использовать для измерения этого использования процессора Thread (кроме диспетчера задач)?
Ответы
Ответ 1
Как уже говорилось, ваш цикл не будет обрабатывать CPU.
Но будьте осторожны: Windows - это не операционная система, поэтому вы не получаете 1000 запросов в секунду от Thread.Sleep(1). Если вы не использовали timeBeginPeriod, чтобы установить минимальное разрешение, вы будете просыпаться каждые 15 мс. Даже после того, как вы установили минимальное разрешение на 1 мс, вы все равно будете просыпаться каждые 3-4 мс.
Чтобы получить гранулярность таймера уровня миллисекунды, вы должны использовать мультимедийный таймер Win32 (С# wrapper).
Ответ 2
Нет, он не будет зависеть от процессора, он просто остановит ваш поток как минимум надолго. Пока ваш поток приостановлен, операционная система может назначить другой, несвязанный поток, чтобы использовать процессор.
Ответ 3
Thread.Sleep(1), как указано, не будет обрабатывать CPU.
Вот что происходит, когда поток спит (более или менее):
- Thread.Sleep транслируется в системный вызов, который, в свою очередь, запускает ловушку (прерывание, которое позволяет операционной системе принимать контроль)
- Операционная система обнаруживает вызов в режиме сна и отмечает, что поток заблокирован.
- Внутри ОС хранится список потоков, которые необходимо пробудить и когда это произойдет.
- Поскольку поток больше не использует CPU, OS...
- Если родительский процесс не исчерпал весь свой временной срез, ОС планирует запланировать еще один поток процесса для выполнения.
- В противном случае начнется выполнение другого процесса (или незанятого процесса).
- Когда время истечет, ваш поток будет снова запланирован для выполнения, что не означает, что он начнет выполнение автоматически.
В заключительной заметке я точно не знаю, что вы делаете, но, похоже, вы пытаетесь взять на себя роль планировщика, то есть спать, чтобы предоставить процессору время для выполнения других задач..
В некоторых случаях (очень немногие) все может быть в порядке, но в основном вы должны позволить планировщику выполнять свою работу, вероятно, знает больше, чем вы,, а может сделать работа лучше, чем вы можете это сделать.
Ответ 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);
Проверяя это в приложении С# GUI, я обнаружил, что приложение использует около 50% моего процессора.
Подробнее об этом разделе см. в следующей теме:
http://www.dotnet247.com/247reference/msgs/57/289291.aspx
Ответ 5
Следует избегать малого времени сна, так как поток, отбрасывающий свой временной срез, получает повышение приоритета при отсрочке, что может привести к высоким контекстным переключателям. В многопоточном/серверном приложении это может привести к эффекту "трещин", поскольку потоки сражаются за процессорное время. Вместо этого полагайтесь на асинхронные функции и объекты синхронизации, такие как критические разделы или мьютексы/семафоры.
Ответ 6
Это старый поток, который появляется во многих моих поисках, но 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
Изменить: помните, sleep (x) не означает пробуждение в это время, это означает разбудить меня не раньше, чем на этот раз. Это не гарантировано. Хотя вы можете увеличить приоритет потока, и Windows должна запланировать ваш поток до потоков с более низким приоритетом.
Ответ 7
Нет, он не будет запугать весь доступный CPU, потому что спящий поток будет отключен планировщиком ОС, когда другой поток будет работать.
Ответ 8
Нет, не будет. Вы это почти не увидите. Где-то менее 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. Я полагаю, что С# должен быть примерно таким же. Я предполагаю, что кто-то отчитается с номерами С# для этого чрезвычайно важного эталона. Кстати, никакого наблюдаемого использования ЦП не наблюдалось.
Ответ 9
Нить может в любой момент запускать один (логический) процессор. И сон на 1 мс не будет болеть. Не потейте.
Ответ 10
также взгляните на это: 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);
}
}