Вопрос по thread-sleep, c#, vb.net, multithreading, blocking – Будет ли зацикливание Thread.Sleep () плохим для производительности, когда используется для приостановки потока?

5

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

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

Операции ввода / вывода - это просто запись блоков размером 4096 байт в файл до тех пор, пока в него не будут записаны все данные. Поскольку файл может быть большим и занимать много времени, я хочу иметь возможность приостановить операцию (в случае, если он начнет потреблять много системных ресурсов).

Мой код, версия VB.NET:

'Class level.
Private BytesWritten As Long = 0
Private Pause As Boolean = False

'Method (thread) level.
While BytesWritten < [target file size]
    ...write 4096 byte buffer to file...

    While Pause = True
        Thread.Sleep(250)
    End While

    ...do some more stuff...
End While

C # эквивалент:

//Class level.
long bytesWritten = 0;
bool pause = false;

//Method (thread) level.
while(bytesWritten < [target file size]) {
    ...write 4096 byte buffer to file...

    while(pause == true) {
        Thread.Sleep(250);
    }

    ...do some more stuff...
}

Я слышал о ResetEvents и немного знаю о том, что они делают, но я никогда особо не разбирался в них.

Я бы использовал событие ручного сброса. После каждого куска ждите события. Чтобы приостановить поток, сбросьте событие. Чтобы возобновить поток, установите событие. Raymond Chen
@EricLippert: Это если пользователь моего приложения хочет приостановить его, потому что операция может потреблять много системных ресурсов. Visual Vincent
Я не понимаю, почему вы хотели быПауза a длительная эксплуатация, Конечно, это займет больше времени. Если вы хотите, чтобы файл записывался асинхронно, то почему бы просто не использовать асинхронный ввод-вывод файла и дождаться результата? Eric Lippert

Ваш Ответ

4   ответа
1

я неправильно понимаю, чего вы пытаетесь достичь здесь, но из того, что я вижу, кажется, что вы пытаетесь заблокировать поток, пока не завершится задача ввода-вывода. Семафоры будут лучшим выбором здесь, вместо того, чтобы использовать Thread.Sleep ().

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

И Thread.Sleep (), и блокирующие семафоры переводят поток в спящий режим, но последний делает это постоянно, пока ресурс не будет освобожден (семафор был подписан). Первый требует, чтобы поток постоянно просыпался, проверял и снова ложился спать. Последний сохраняет эти циклы выполнения.

Мне все еще нравится, что вы очень много отвечаете, но вместо этого я отметил ответ dbasnett как принятый, так как он лучше подходит для моего использования.ManualResetEvent позволяет / блокирует только один вызов, в то время как при использованииSemaphore Вы должны указатьКак много это должно позволить, пока это не блокирует. Visual Vincent
Отличный ответ! Короткие и понятные объяснения! Visual Vincent
Извините за то, что неясно. Я не пытаюсь заблокировать, пока операция ввода / вывода не закончится, я пытаюсь приостановить операцию ввода / вывода. Я в основном записываю буферы данных в файл до тех пор, пока все данные не будут записаны, так как это может занять некоторое время, чтобы я смог приостановить эту работу. Visual Vincent
Я также обновил свой вопрос с этим объяснением. Visual Vincent
3

Я думаю, основываясь на описании, я бы сделал это

'Class level.
Private BytesWritten As Long = 0
Private NotPaused As New Threading.ManualResetEvent(True)

Изменение имени переменной подходит, так как это будет использоваться

    'Method (thread) level.
     While BytesWritten < [target file size]
        '...write 4096 byte buffer to file...

        NotPaused.WaitOne(-1)

        '...do some more stuff...
    End While

Чтобы сделать паузу цикла, сделайте это

    NotPaused.Reset()

и продолжить

    NotPaused.Set()
Спасибо. Это решение подходит лучше, так какManualResetEvent является только «открытым» или «закрытым», кромеSemaphore который, кажется, открыт дляx количество звонков. Теперь вы также научили меня, какManualResetEvents Работа! Visual Vincent
2

В .NET нет причин использовать Thread.Sleep, кроме попытки имитировать длительные операции во время тестирования и / или отладки в потоке MTA, поскольку он будет блокироваться.

Возможно, другой вариант будет использоватьTPL, Так как вы не хотите блокировать, вы можете использоватьTask.Delay, Как вы, вероятно, знаете, Задача представляет собой асинхронную операцию.

1

что более элегантный способ - заставить поток спать бесконечно, пока он не проснется другим потоком, вызывающим Thread.Interrupt в первом потоке, который спит. Вот хороший пример этого с примером кода:Приостановка и возобновление потоков.

Спасибо за ответ. Но я, как и Гроо, знал об этомThread.Interrupt() может вызвать проблемы. Visual Vincent
Спасибо за исправление @Groo, я должен был также подумать о лучших практиках (что можно и чего нельзя делать) при ответе на вопрос. Timo Salomäki
Прерывание потоков - плохая идея, которая может легко привести к тупикам. Groo

Похожие вопросы