【问题标题】:How to make SqlDataReader thread safe / convert to thread safe type如何使 SqlDataReader 线程安全/转换为线程安全类型
【发布时间】:2016-11-11 02:43:19
【问题描述】:

我正在处理一个用 VB.Net 编写的遗留应用程序。我的任务是使用并行任务库并线程化应用程序。大部分“工作”在一个以 SqlDataReader 对象为中心的 while 循环中。值得称赞的是,它被分解为逻辑方法和一种真正的工作方法。主要问题是处理单个任务的所有方法都接受 SqlDataReader 作为参数。我知道 SqlDataReader 并不是真正的线程安全的,而且它的使用方式根本不是线程安全的。我想做的就是将 SqlDataReader 转换为 ConcurrentQueue 或 IEnumerable,然后让“工作”线程处理该集合中的数据:

Using Command As New SqlCommand(StoredProcedure, Connection)
Command.CommandType = CommandType.StoredProcedure
Command.CommandTimeout = 0
Command.Parameters.Add("@Carrier", SqlDbType.VarChar, 50).Value = sCarrier
Using Reader As SqlDataReader = Command.ExecuteReader
    If Reader.HasRows = True Then
        SetReaderOrdinals(Reader)
        Adjustments = New StringBuilder


        'TODO this appears to be the bulk of the work in the application
        While Reader.Read
            Adjustments.Clear()
            CommitCount += 1
            If Reader.IsDBNull(SomeValue) = False Then
                Select Case stuff
                    Case 1
                        DoThingForOne(Reader)
                    Case 2
                        DoThingForTwo(Reader)
                    Case 3
                        DoThingForThree(Reader)
                    Case 4
                        DoThingForFour(Reader)
                    Case 5
                        DoThingForFive(Reader)
                    Case 6
                        DoThingForSix(Reader)
                    Case Else
                        'Log something
                        Exit While
                End Select
            Else
                'We Failed
            End If
        End While

在这些方法中,rdr 在这些方法中被执行,例如:

If Rdr.GetString(SomeValue).Trim.Length >= 5 Then

If Rrd.IsDBNull(SomeValue)

Rrd.GetInt32(SomeValue)

我想做的是这样的:

'I know this isn't how you convert it but I am not sure how you do
Dim rows AS IEnumerable(of MyObject) = Reader

'Create threads and spawn them here

'act upon the collection here in many threads
Parallel.For Each row in rows
    'Do row stuff here 
    If row Not Nothing Then 
                Select Case stuff
                    Case 1
                        DoThingForOne(row)
                    Case 2
                        DoThingForTwo(row)
                    Case 3
                        DoThingForThree(row)
                    Case 4
                        DoThingForFour(row)
                    Case 5
                        DoThingForFive(row)
                    Case 6
                        DoThingForSix(row)
                    Case Else
                        'Log something
                        Exit For
                End Select
            Else
                'We Failed
            End If
        End For

我不确定这是否合理或最好的处理方式,但这是我首先想到的。

有什么建议吗?

【问题讨论】:

    标签: vb.net refactoring task-parallel-library


    【解决方案1】:

    如果您将数据库阅读器代码放入迭代器函数中,这将为您提供将其转换为 IEnumerable 的方法,例如

    Iterator Function ReadMyObjects() As IEnumerable(Of MyObject)
        Using cn = New SqlConnection("...")
            cn.Open()
            Using cmd = New SqlCommand("...", cn)
                Using rdr = cmd.ExecuteReader()
                    If rdr.HasRows Then
                        While rdr.Read()
                            Yield New MyObject() With {
                                .PropA = rdr.GetString(rdr.GetOrdinal("A"))
                            }
                        End While
                    End If
                End Using
            End Using
        End Using
    End Function
    

    然后您可以在并行循环中使用它:

    Parallel.ForEach(
        ReadMyObjects(),
        Sub(item As MyObject)
            ' do something with item
        End Sub
    )
    

    【讨论】:

    • 我喜欢这种方法;但是,我不明白你在循环中做了什么。我主要是一个 C# 开发人员,我只是用 VB 来实现它。我知道底层代码是一样的。你在那里用 Sub(item) 部分做什么?这与 C# 中的 ReadMyObjects() 中的 var item 相同吗?
    • Sub(item) 部分是 lambda expression - C# 等效项类似于 Parallel.ForEach(ReadMyObjects(), item => { // do something here })。对于ReadMyObjects 返回的每个项目,将调用一次 sub - 这将在多个线程上并行发生。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-29
    • 1970-01-01
    • 2012-06-19
    • 1970-01-01
    • 2021-07-12
    • 2011-03-30
    相关资源
    最近更新 更多