Спинвейт против ожидания сна. Какой из них использовать?



Является ли это эффективным для



SpinWait.SpinUntil(() => myPredicate(), 10000)


Для таймаута 10000ms



Или



Эффективнее ли использовать Thread.Sleep опрос для того же условия
Например, что-то вроде следующей функции SleepWait:



public bool SleepWait(int timeOut)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
while (!myPredicate() && stopwatch.ElapsedMilliseconds < timeOut)
{
Thread.Sleep(50)
}
return myPredicate()
}


Я обеспокоен тем, что вся отдача SpinWait может не быть хорошей моделью использования, если мы говорим о таймаутах в течение 1 секунды? Является ли это справедливым предположением?



Какой подход вы предпочитаете и почему? Есть ли другой еще лучше подходить?



Update - становится более конкретным:



Есть ли способ сделать блокирующий импульс сбора спящим потоком, когда он достигает ограниченной емкости? Я предпочитаю избегать напряженного ожидания всех вместе, как предлагает Марк Гравел.

558   2  

2 ответов:

Лучшийподход состоит в том, чтобы иметь некоторый механизм для активного обнаружениятого, что становится истинным (а не пассивно опрашивать его, когда становитсяистинным); это может быть любой вид дескриптора ожидания, или, возможно, Task с Wait, или, возможно, event, на который вы можете подписаться, чтобы отклеить себя. Конечно, если вы делаете что-то вроде "подождите, пока что-то не произойдет", это все равно не так эффективно, как просто выполнить следующий бит работы в качестве callback , что означает: вам не нужно использовать поток для ожидания. Task имеет ContinueWith для этого, или вы можете просто сделать работу в event, когда его уволят. event, вероятно, самый простой подход, в зависимости от контекста. Task, однако, уже предоставляет почти все, о чем вы здесь говорите, включая механизмы "ожидания с таймаутом" и "обратного вызова".

И да, вращение в течение 10 секунд не велико. Если вы хотите использовать что-то вроде вашего текущего кода, и если у вас есть причина ожидать короткой задержки, но нужно учитывать более длинную-может быть, SpinWait для (скажем) 20 мс, а использовать Sleep для остальных?


Re комментарий; Вот как я бы зацепил механизм "is it full":

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

С, в коде "положить обратно в коллекцию":

if(CollectionIsFull) {
    lock(syncLock) {
        if(CollectionIsFull) { // double-check with the lock
            Monitor.PulseAll(syncLock);
        }
    }
}

В .NET 4 SpinWait выполняет интенсивное вращение процессора в течение 10 итераций, прежде чем дать результат. Но он не возвращается к вызывающему объекту сразу после каждого из этих циклов; вместо этого он вызывает Thread.SpinWait для запуска через CLR (по сути, ОС) в течение заданного периода времени. Этот период времени первоначально составляет несколько десятков наносекунд, но удваивается с каждой итерацией, пока не завершатся 10 итераций. Это обеспечивает ясность / предсказуемость в общей затраченной фазе вращения (интенсивной для процессора), которая система может настраиваться в соответствии с условиями(количество ядер и т.д.). Если SpinWait остается в фазе спина слишком долго, он периодически будет спать, чтобы позволить другим потокам продолжить работу (см. блог Дж.Альбахари для получения дополнительной информации). Этот процесс гарантированно держит ядро занятым...

Таким образом, SpinWait ограничивает процессорный спин заданным числом итераций, после чего он дает свой временной срез на каждом спине (фактически вызывая Thread.Yield и Thread.Sleep), снижая свой ресурс потребление. Он также определит, работает ли пользователь на одной базовой машине, и даст результат на каждом цикле, если это так.

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

Comments

    Ничего не найдено.