SpinWait против ожидания сна. Какой из них использовать?
эффективно ли
SpinWait.SpinUntil(() => myPredicate(), 10000)
для тайм-аута 10000ms
или
это более эффективно использовать Thread.Sleep
опрос для того же условия
Например что-то вроде следующего :
public bool SleepWait(int timeOut)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
while (!myPredicate() && stopwatch.ElapsedMilliseconds < timeOut)
{
Thread.Sleep(50)
}
return myPredicate()
}
Я обеспокоен тем, что вся отдача SpinWait не может быть хорошей моделью использования, если мы говорим о таймаутах в течение 1 сек? Это правильное предположение?
какой подход вы предпочитаете и зачем? Есть ли другой, еще лучший подход?
обновление - становясь более конкретным:
есть ли способ сделать импульс BlockingCollection спящим потоком, когда он достигает ограниченной емкости? Я предпочитаю избегать занятого ожидания все вместе, как предлагает Марк гравий.
2 ответа:
The лучшие подход должен иметь какой-то механизм активно обнаруживать вещь становится правдой (вместо того, чтобы пассивно опрашивать ее, имея стать true); это может быть любой вид wait-handle, или, может быть,
Task
СWait
, илиevent
что вы можете подписаться на отклеить себя. Конечно, если вы делаете что-то вроде "подождите, пока что-то не произойдет", то есть еще не так эффективно, как просто иметь следующий бит проделанной работы как обратный вызов, что означает: вам не нужно использовать нить, чтобы ждать.Task
иContinueWith
для этого, или вы можете просто сделать работу вevent
когда он будет уволен. Элементevent
- Это, наверное, самый простой подход, в зависимости от контекста.Task
, однако, уже предоставляет большинство-все, о чем вы говорите здесь, включая механизмы "ожидания с таймаутом" и "обратного вызова".и да, вращение в течение 10 секунд не очень хорошо. Если вы хотите использовать что - то вроде вашего текущего кода, и если у вас есть основания ожидать небольшую задержку, но нужно разрешить более длинный-возможно
SpinWait
на (скажем) 20 мс, и использоватьSleep
для остальных?
Re комментарий; Вот как я бы крючок" это полный " механизм:
private readonly object syncLock = new object(); public bool WaitUntilFull(int timeout) { if(CollectionIsFull) return true; // I'm assuming we can call this safely lock(syncLock) { if(CollectionIsFull) return true; return Monitor.Wait(syncLock, timeout); } }
С, в коде" put back into the collection":
if(CollectionIsFull) { lock(syncLock) { if(CollectionIsFull) { // double-check with the lock Monitor.PulseAll(syncLock); } } }
в .NET 4
SpinWait
выполняет CPU-интенсивное вращение в течение 10 итераций перед выходом. Но он не возвращается к вызывающему тут после каждого из этих циклов; вместо этого, он называетThread.SpinWait
для вращения через CLR (по существу, ОС) в течение заданного периода времени. Этот период времени первоначально составляет несколько десятков нано-секунд, но удваивается с каждой итерацией до завершения 10 итераций. Это обеспечивает ясность / предсказуемость в общей фазе времени, затраченного на вращение (интенсивный процессор) , который система может настроить в соответствии с условиями (количество ядер и т. д.). ЕслиSpinWait
по-прежнему в спин-урожайный участок слишком долго он будет периодически спать, чтобы позволить другим потокам (см. Albahari J. В блог для получения дополнительной информации). Этот процесс гарантированно держать ядро занят...и
SpinWait
ограничивает интенсивное вращение процессора заданным числом итераций, после чего он дает свой временной срез на каждом вращении (фактически вызываяThread.Yield
иThread.Sleep
), снизив ее потребление ресурсов. Он также определит, работает ли пользователь на одноядерной машине и выходит на каждый цикл, если это так.С
Thread.Sleep
поток блокируется. Но этот процесс не будет таким дорогим, как выше с точки зрения процессора.