2016-11-10 6 views
2

VB.Netで書かれた従来のアプリケーションを扱っています。 Paralelタスク・ライブラリーを使用してアプリケーションをスレッド化することが任されています。 "作業"の大部分は、SqlDataReaderオブジェクトを中心とするループ中にあります。開発者の信用のために、それは論理的な方法と実際の作業方法に分かれています。大きな問題は、個々のタスクを処理するすべてのメソッドがSqlDataReaderをパラメータとして受け入れることです。私は、SqlDataReaderは実際にスレッドセーフではなく、そのスレッドセーフではないということを知っています。私は私が考えてやりたいことはConcurrentQueueまたはIEnumerableをへSqlDataReaderの変換された後、ちょうどそのコレクション内のデータの「仕事」スレッドと仕事を持っている: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がで作用されますこれらのメソッドexは:

'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 

私は、これがもっともらしいか、これを処理するための最良の方法であるかどうかわからないのですが、それは最初番目です:

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

If Rrd.IsDBNull(SomeValue) 

Rrd.GetInt32(SomeValue) 

私は何をしたいことは何かに似ていますそれが心に来た。

何か提案がありますか?

答えて

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#devであり、私はVBでそれをウィングしています。私は基になるコードが同じであることを知っています。 Sub(item)の部分はどうしていますか? ReadMyObjects()内のvar itemをC#と言っているのと同じですか? – Robert

+1

'Sub(item)'の部分は[ラムダ式](https://msdn.microsoft.com/en-us/library/bb531253.aspx)です.C#相当のものは 'Parallel.ForEach(ReadMyObjects ()、item => {//ここで何か}) '。 'ReadMyObjects'によって返された各項目に対してsubは一度呼び出されます。これは複数のスレッドで並列に発生します。 – Mark

関連する問題