Это плохая идея, чтобы помещать частые операции ввода-вывода файла в блок SyncLock? - PullRequest
4 голосов
/ 14 сентября 2009

Скажем, у меня есть код, который делает это:

Public Function AppendToLogFile(ByVal s As String) As Boolean
    Dim success As Boolean = True
    Dim fs As IO.FileStream = Nothing
    Dim sw As IO.StreamWriter = Nothing

    Static LogFileLock As New Object()
    SyncLock LogFileLock
        Try
            fs = New IO.FileStream(LogFilePath)
            sw = New IO.StreamWriter(fs)
            sw.WriteLine(s)

        Catch ex As Exception
            success = False

        Finally
            If Not sw Is Nothing Then sw.Close()
            If Not fs Is Nothing Then fs.Close()
        End Try
    End SyncLock

    Return success
End Function

Прежде всего: проблема в том, что у меня есть блок Try / Catch / finally внутри SyncLock?

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

Ответы [ 2 ]

4 голосов
/ 14 сентября 2009

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

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

Public NotInheritable Class Log

    Private Shared m_LogLock As New Object
    Private Shared m_Log As StreamWriter

    Public Shared Sub WriteLog(ByVal message As String)
        SyncLock m_LogLock
            If m_Log Is Nothing Then
                m_Log = New StreamWriter("pathAndFileName")
            End If
            m_Log.WriteLine(message)
            m_Log.Flush()
        End SyncLock
    End Sub

End Class
4 голосов
/ 14 сентября 2009

На первый взгляд, все в порядке, с двумя оговорками:

  1. Статические члены используют своего рода поточно-ориентированную блокировку уже за кулисами. Таким образом, вместо явной блокировки вы можете просто использовать существующую блокировку. Хотя я не совсем уверен, как это будет выглядеть.
  2. Не возвращать коды состояния. Пусть исключение распространяется до соответствующего уровня. Как только вы это сделаете, вы можете переписать свой код следующим образом:

.

Public Sub AppendToLogFile(ByVal s As String) As Boolean
    Static LogFileLock As New Object()
    SyncLock LogFileLock
        Using sw As New IO.StreamWriter(LogFilePath)
            sw.WriteLine(s)
        End Using
    End SyncLock
End Sub

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

...