2016-11-10 4 views
2

Я имею дело с устаревшим заявлением, написанным на VB.Net. Мне было поручено использовать библиотеку задач Paralel и потоковое приложение. Основная часть «работы» находится в одном цикле, который центрируется вокруг объекта SqlDataReader. К чести разработчика он разбит на логические методы и один реальный метод работы. Основная проблема заключается в том, что все методы, которые обрабатывают отдельные задачи, принимают 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 

Внутри этих методов РДР действует в те методы например:

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# dev, и я просто прикрываю его VB. Я знаю, что базовый код тот же. Что вы делаете с частью Sub (item) там? Это то же самое, что и в C#, указывающем элемент var в ReadMyObjects()? – Robert

+1

Элементы 'Sub (item)' являются [лямбда-выражением] (https://msdn.microsoft.com/en-us/library/bb531253.aspx) - эквивалент C# будет похож на 'Parallel.ForEach (ReadMyObjects(), item => {// делаем что-то здесь}) '. Sub будет вызываться один раз для каждого элемента, возвращаемого 'ReadMyObjects', и это будет происходить параллельно по нескольким потокам. – Mark