1

私は初心者なので、これがばかげた質問である場合はご容赦ください... WMI 情報 (この場合は OS 情報) をプルして、フォームの ListView を更新するマシンのリストがあります。おそらくTask Factoryを使用して、次のコードを効率的な方法でマルチスレッド化する最も簡単な方法を探していますか? 私が読んだことから、各コンピューターをコレクションに入れる必要があり、各スレッドがコレクション内のオブジェクトを更新する必要があるように見えますか?

これが私の元のコードです:

Imports System.Management

Public Class Form1
Public PC As New pc
Public WMI As New WMIConnect
Public i As Integer = 1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    With lv_Inventory
        .Visible = True
        .UseCompatibleStateImageBehavior = False
        .View = View.Details
        .Scrollable = True
        .Sort()
        .HideSelection = False
        .FullRowSelect = True
        .GridLines = True
        .AllowColumnReorder = True
        .Columns.Add("Name", 100)
        .Columns.Add("LastBoot", 150)
        .Columns.Add("OS", 125)
        .Columns.Add("Version", 100)
        .Columns.Add("SP", 75)
    End With

    For Each Machine As ListViewItem In lv_Machines.SelectedItems
        lv_Inventory.Items.Add(Machine.Text)
        'Dim PC As New pc
        WMI.WMIConnect(Machine.Text, tb_user.Text, tb_pass.Text)
        PC.Name = Machine.Text
        GetOS()
        lv_Inventory.Items(i - 1).SubItems.Add(PC.LastBootTime)
        lv_Inventory.Items(i - 1).SubItems.Add(PC.OperatingSystem)
        lv_Inventory.Items(i - 1).SubItems.Add(PC.OSVersion)
        lv_Inventory.Items(i - 1).SubItems.Add(PC.ServicePack)
        i += 1
    Next

End Sub

Public Sub GetOS()

    On Error Resume Next
    Dim lastboot As String = Nothing
    Dim m As ManagementObject
    Dim queryCollection As ManagementObjectCollection
    queryCollection = wmi.wmiQuery _
    ("SELECT Caption, Lastbootuptime, version, csdversion, csname, SystemDirectory FROM   Win32_OperatingSystem")

    If queryCollection Is Nothing Then
        ' Me.LostConnection()
        Exit Sub
    End If

    For Each m In queryCollection
        pc.Hostname = UCase(m("csname"))
        pc.LastBootTime = m("LastBootUpTime")
        pc.OSVersion = m("Version")
        pc.ServicePack = m("CSDVersion")
        pc.OperatingSystem = m("Caption")
    Next
End Sub

End Class


Public Class WMIConnect
Public Shared wmiScope As Management.ManagementScope
Public Shared RegScope As Management.ManagementScope

Public Sub WMIConnect(ByVal Machine As String, ByVal Username As String, ByVal Pass As String)
    Dim wmiConnectionOptions As New Management.ConnectionOptions

    With wmiConnectionOptions
        .Impersonation = System.Management.ImpersonationLevel.Impersonate
        .Timeout = New TimeSpan(0, 0, 10)
        .Authentication = System.Management.AuthenticationLevel.Packet
        .Username = Username
        .Password = Pass
        .EnablePrivileges = True
    End With

    Try
        Dim wmiScope As New Management.ManagementScope("\\" & _
                   Machine & "\root\cimv2", wmiConnectionOptions)
        wmiScope.Connect()
        Dim RegScope As New Management.ManagementScope("\\" & _
                   Machine & "\root\default:StdRegProv", wmiConnectionOptions)
        RegScope.Connect()
    Catch e As Exception
        MsgBox("Error: " & e.ToString)
    End Try


End Sub

Public Function wmiQuery(ByVal QueryString As String) As Management.ManagementObjectCollection
    Try
        Dim query As Management.ObjectQuery
        query = New Management.ObjectQuery(QueryString)
        Dim searcher As Management.ManagementObjectSearcher
        searcher = New Management.ManagementObjectSearcher(wmiScope, query)
        Dim queryCollection As Management.ManagementObjectCollection
        queryCollection = searcher.Get()
        Return queryCollection
    Catch
        Dim queryCollection As Management.ManagementObjectCollection = Nothing
        Return queryCollection
    End Try

End Function
End Class


Public Class pc

Public Shared Name As String
Public Hostname As String
Public OperatingSystem As String
Public ServicePack As String
Public OSVersion As String
Public LastBootTime As String

End Class

並列タスクの更新されたコードは次のようになります。

        Parallel.ForEach(lv_Machines.SelectedItems.Cast(Of Object), _
                 Sub(machine)

                     ' ... work with currentElement
                     Try
                         Dim WMI As New wmiConnection
                         Dim PC As New pc
                         Dim i As Integer = 1
                         Dim int As Integer = 1
                         tb_Log.Text += "working on machine " & machine.text & vbCrLf
                         WMI.WMIConnect(machine.Text, tb_user.Text, tb_pass.Text)
                         tb_Log.Text += "WMI connect to machine " & machine.text & vbCrLf
                         PC.Name = machine.Text
                         GetOS(PC, WMI)
                         GetHardware(PC, WMI)
                         GetNetwork(PC, WMI)

                         With lv_Inventory
                             .Items.Add(PC.Name.ToString)
                             With .Items(.Items.Count - 1).SubItems
                                 .Add(PC.LastBootTime.ToString & "")
                                 .Add(PC.OperatingSystem.ToString & "")
                                 .Add(PC.OSVersion.ToString & "")
                                 .Add(PC.ServicePack.ToString & "")
                                 .Add(PC.SerialNumber.ToString & "")
                                 .Add(PC.ChassisType.ToString & "")
                                 .Add(PC.CPU.ToString & "")
                                 .Add(PC.PhysicalMemory.ToString & "")
                                 .Add(PC.Model.ToString & "")
                                 .Add(PC.Manufacturer.ToString & "")
                                 .Add(PC.MacAddress.ToString & "")
                             End With
                         End With

                         tb_Log.Text += "Processing: " & machine.Text & " Thread ID: " & Thread.CurrentThread.ManagedThreadId & vbCrLf
                     Catch ex As Exception
                         tb_Log.Text += "Error: " & ex.ToString & vbCrLf
                     End Try

                 End Sub)

新しいコードでは、スレッド同期の問題と戦っている可能性があると思います...トレースログは、WMIオブジェクトが前/次のタスクによって上書きされているように見えることを示しているようで、リストビューの最終的な情報はちょうど終わっています最後に作成して接続した PC オブジェクトと同じ結果セットを持つ (競合状態に陥る)。WMI 接続で同期ロックを実行し、データの取得が完了したら解放する必要がありますか? もしそうなら、WMI オブジェクトと PC オブジェクトの両方をロックする必要があるため、非マルチスレッドの for/each よりもはるかに高速でしょうか? 基本的には、コンピューターのリストを取得してそれぞれに接続し、マルチスレッドで詳細を取得する方法が必要なだけです。私のトレースログの出力は次のとおりです。

  1. マシン col-01 で作業中
  2. マシン col-02 で作業中
  3. マシン WI-01 への WMI 接続
  4. CPU 情報を取得中... WI-01 用
  5. ドライブ情報を取得しています... for WI-01
  6. エンクロージャ タイプを取得しています。WI-01用
  7. 処理: WI-01 スレッド ID: 10
  8. マシン sta-01 への WMI 接続
  9. マシン sta-02 への WMI 接続
  10. CPU情報取得中… WI-01
  11. CPU 情報を取得しています... WI-01
  12. ドライブ情報を取得しています... WI-01
  13. ドライブ情報を取得しています... WI-01
  14. エンクロージャ タイプを取得しています。WI-01用
  15. エンクロージャ タイプを取得しています。WI-01用
  16. 処理: sta-01 スレッド ID: 9
  17. 処理: sta-02 スレッド ID: 6
4

1 に答える 1

0

Well, probably the easiest way would be to use Threaded.ForEach . You can find details here:

http://msdn.microsoft.com/en-us/library/dd460720(v=vs.100).aspx

That requires .net4 or greater.

于 2012-11-19T05:32:39.077 に答える