2016-07-23 1 views
5

Существует (или было) много разговоров о том, как хорошо или плохо использовать метод Thread.Sleep(). Из того, что я понимаю, в основном используется для целей отладки.Будет ли цикл 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, и я знаю немного о том, что они делают, но я никогда на самом деле много смотрел на них.

+2

Я бы использовал событие ручной перезагрузки. После каждого фрагмента подождите события. Чтобы приостановить поток, сбросьте событие. Чтобы возобновить поток, установите событие. –

+2

Я не понимаю, почему вы хотите * pause * a * long operation *. Несомненно, это заставит его заняться больше времени. Если вы хотите, чтобы файл был написан асинхронно, то почему бы просто не использовать асинхронный файл IO и ждать результата? –

+1

@EricLippert: Это значит, что пользователь моего приложения хочет приостановить его, потому что операция может много использовать системные ресурсы. –

ответ

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() 

и c c ontinue

NotPaused.Set() 
+1

Спасибо. Это решение подходит лучше, так как «ManualResetEvent» является только «открытым» или «закрытым», кроме «Семафора», который, кажется, открывается для _x_ количества вызовов. Теперь вы также немного научили меня тому, как работает «ManualResetEvents»! –

1

Я думаю, что более элегантным способом является то, что поток будет бесконечно бесконечным, пока он не проснется другим потоком, вызывающим Thread.Interrupt на первом потоке, который спит. Это хороший пример этого примера с кодом: Pausing and Resuming Threads.

+1

Прерывающие потоки - плохая идея, которая может легко привести к взаимоблокировкам. – Groo

+0

Спасибо за ответ. Но я, как и Гроо, знал, что 'Thread.Interrupt()' может вызвать проблемы. –

+0

Благодарим вас за исправление @Groo, я должен был подумать о лучших практиках (делать и не делать), отвечая на вопрос. – hankide

1

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

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

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

+0

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

+0

Я также обновил свой вопрос с этим объяснением. –

+0

Отличный ответ! Короткие и легко понятные объяснения! –

2

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

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