【问题标题】:Is it a bad idea to put frequent file I/O operations within a SyncLock block?将频繁的文件 I/O 操作放在 SyncLock 块中是不是一个坏主意?
【发布时间】:2009-09-14 18:04:47
【问题描述】:

假设我有一些代码可以做到这一点:

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

首先:我在 SyncLock 内有 Try/Catch/Finally 块是否存在问题?

其次:假设这段代码在一个事件上运行,可能会在很短的时间内运行很多次——比如说,在一秒钟内运行十次。像这样让它 SyncLock 是否可以,或者让它在队列中添加一行,然后将队列中的所有行写入文件中的文件,例如每秒关闭一次?

【问题讨论】:

    标签: .net vb.net file-io try-catch synclock


    【解决方案1】:

    乍一看,这看起来不错,但有两个警告:

    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
    

    这就是不到一半代码中的所有功能。唯一的区别是你必须在调用代码中处理异常而不是检查返回状态。

    【讨论】:

      【解决方案2】:

      在您的情况下,只要日志文件相对不频繁地写入,锁定就可以了。换句话说,如果每个成功的操作都写入日志,那可能不是一个好的设计。如果只有失败的操作写入日志,那么它可能绰绰有余。

      此外,如果您经常写入此日志,您可能希望在共享变量中引用 `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
      

      【讨论】:

      • 如果你要去共享,你还不如去本地静态。你也可以锁定它(在 VB.Net 中,本地静态是共享的,并通过 Monitor.Enter/Exit 自动保护)
      • 只有静态的初始化是自动保护的(参见 MSIL)。对于这种情况,这还不够。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-02-19
      • 1970-01-01
      • 2012-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-17
      相关资源
      最近更新 更多