2016-11-10 50 views
2

我正在处理用VB.Net编写的遗留应用程序。我的任务是使用Paralel任务库和线程应用程序。大部分“工作”都在一个以SqlDataReader对象为中心的while循环中。为了开发人员的信任,它被分解为逻辑方法和一个真正的工作方法。主要的问题是处理单个任务的所有方法都接受SqlDataReader作为参数。我知道SqlDataReader并不是真正的线程安全的,它的使用方式并不是线程安全的。我想要做的,我认为是SqlDataReader对象转换为ConcurrentQueue或IEnumerable的,然后就必须对收集的数据的“工作”线程和工作:如何使SqlDataReader线程安全/转换为线程安全类型

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 

我不知道这是否是合理的或者处理的最佳方式,但它是第一届想到的就是这些。

有什么建议吗?

回答

2

如果你把你的数据库的读者的代码到一个迭代器的功能,这将使你把它转换为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 
) 
+0

我喜欢这种方法;但是,我不明白你在循环中做什么。我主要是一个C#开发人员,我只是用VB来装备它。我知道底层代码是相同的。你在那里用Sub(item)部分做什么?这与C#中的ReadMyObjects()中的var项相同吗? – Robert

+1

的'子(项目)'份为一λ表达式](https://msdn.microsoft.com/en-us/library/bb531253.aspx) - 的C#等效会是这样'Parallel.ForEach(ReadMyObjects (),item => {//在这里做些什么})。对于由'ReadMyObjects'返回的每个项目,子将被调用一次 - 这将在多个线程上并行发生。 – Mark