2016-11-10 73 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