VB.net에서 멀티 스레딩에 대해 배우기 위해 간단한 테스트 프로그램을 작성했습니다. 조사하고, 시도하고, 실패한 많은 일들을 겪은 후에, 나는 최소한 내 프로그램을 운영하고있다.왜 내 작업이 병렬로 실행되지 않습니까?
이제 이상하게 동작하고 이유를 설명 할 수 없습니다. 어쩌면 내 프로그램에 어떤 문제가 있는지, 왜 프로그램이 어떻게 작동하는지, 그리고/또는 프로그램이 제대로 작동하도록하기 위해 바꿔야 만 하는지를 말해 줄 수 있습니다.
내 프로그램에는 각각 다른 스레드에서 실행하려는 장기 실행 작업을 시뮬레이트하는 클래스 (TestClass), 장기 실행 작업 및 기본 프로 시저의 진행 메시지를 표시하는 진행률 형식 (Form1) 이 두 가지를 합친 것입니다.
Public Class Form1
Public Sub AddMessage1(ByVal message As String)
If String.IsNullOrEmpty(message) Then
Exit Sub
End If
Me.ListBox1.Items.Add(message)
Me.ListBox1.SelectedIndex = Me.ListBox1.Items.Count - 1
Application.DoEvents()
End Sub
Public Sub AddMessage2(ByVal message As String)
If String.IsNullOrEmpty(message) Then
Exit Sub
End If
Me.ListBox2.Items.Add(message)
Me.ListBox2.SelectedIndex = Me.ListBox2.Items.Count - 1
Application.DoEvents()
End Sub
End Class
TestClass에 :
Imports System.Threading
Public Class TestClass
Public Event ShowProgress(ByVal message As String)
Private _milliSeconds As UShort
Private _guid As String
Public Sub New(milliSeconds As UShort, ByVal guid As String)
_milliSeconds = milliSeconds
_guid = guid
End Sub
Public Function Run() As UShort
For i As Integer = 1 To 20
RaiseEvent ShowProgress("Run " & i)
Thread.Sleep(_milliSeconds)
Next i
Return _milliSeconds
End Function
End Class
Main 프로 시저이리스트 박스 (에 ListBox1과 ListBox2)를 포함
진행 형태 (Form1에) : 여기
내 코드입니다 : 012 3,516,Imports System.Threading.Tasks
Imports System.ComponentModel
Public Class Start
Private Const MULTI_THREAD As Boolean = True
Public Shared Sub Main()
Dim testClass(1) As TestClass
Dim testTask(1) As Task(Of UShort)
Dim result(1) As UShort
testClass(0) = New TestClass(50, "Test1")
testClass(1) = New TestClass(200, "Test2")
Using frm As Form1 = New Form1
frm.Show()
AddHandler testClass(0).ShowProgress, AddressOf frm.AddMessage1
AddHandler testClass(1).ShowProgress, AddressOf frm.AddMessage2
If MULTI_THREAD Then
testTask(0) = Task(Of UShort).Factory.StartNew(Function() testClass(0).Run, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext)
testTask(1) = Task(Of UShort).Factory.StartNew(Function() testClass(1).Run, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext)
Task.WaitAll(testTask)
result(0) = testTask(0).Result
result(1) = testTask(1).Result
Else
result(0) = testClass(0).Run
result(1) = testClass(1).Run
End If
RemoveHandler testClass(0).ShowProgress, AddressOf frm.AddMessage1
RemoveHandler testClass(1).ShowProgress, AddressOf frm.AddMessage2
frm.Close()
End Using
MessageBox.Show("Result 1: " & result(0) & "; Result 2: " & result(1))
End Sub
End Class
이 프로그램은 진행 양식을 열 병렬로 두 개의 장기 실행 작업을 실행, 두 개의 장기 실행 작업의 진행 메시지를 표시, 장기 실행 작업이 모두 완료되면 진행 양식을 닫고을 표시하도록되어 메시지 상자에 장기 실행 태스크의 결과가 표시됩니다.
이제는 설명 할 수 없습니다.이 프로그램을 실행하면 두 목록 상자 모두에서 "실행 1"이 표시되므로 두 작업이 모두 실행되기 시작하지만 첫 번째 목록 상자 만 채워지고 첫 번째 listbox가 채워지면 (첫 번째 작업이 완료 됨) 두 번째 목록 상자가 계속 채워집니다. 따라서 두 작업 모두 시작되지만 두 번째 작업은 계속 실행하기 전에 첫 번째 작업이 완료 될 때까지 대기합니다.
그러나 내 주 절차에서 Task.WaitAll(testTask)
을 주석 처리하면 다른 방향입니다. 두 목록 상자에 "실행 1"이 표시되고 두 번째 목록 상자가 채워지고 두 번째 목록 상자가 채워질 때만 (두 번째 작업이 완료 됨) 첫 번째 목록 상자가 계속 실행됩니다.
내 프로그램이 왜 이상하게 작동하고 동시에 두 개의 작업을 동시에 실행할 수 있습니까?유일한 대답은 지금까지 나는 내가 제거 사용하고있어 SynchronizationContext
과 관련이 있음을 언급 때문에
업데이트
:-)이 작은 신비를 해결에 도움을 주셔서 감사합니다
Main 프로 시저 :
Imports System.Threading.Tasks
Imports System.ComponentModel
Public Class Start
Private Const MULTI_THREAD As Boolean = True
Public Shared Sub Main()
Dim testClass(1) As TestClass
Dim testTask(1) As Task(Of UShort)
Dim result(1) As UShort
testClass(0) = New TestClass(50, "Test1")
testClass(1) = New TestClass(200, "Test2")
Using frm As Form1 = New Form1
frm.Show()
AddHandler testClass(0).ShowProgress, AddressOf frm.AddMessage1
AddHandler testClass(1).ShowProgress, AddressOf frm.AddMessage2
If MULTI_THREAD Then
testTask(0) = Task(Of UShort).Factory.StartNew(Function() testClass(0).Run)
testTask(1) = Task(Of UShort).Factory.StartNew(Function() testClass(1).Run)
Task.WaitAll(testTask)
result(0) = testTask(0).Result
result(1) = testTask(1).Result
Else
result(0) = testClass(0).Run
result(1) = testClass(1).Run
End If
RemoveHandler testClass(0).ShowProgress, AddressOf frm.AddMessage1
RemoveHandler testClass(1).ShowProgress, AddressOf frm.AddMessage2
frm.Close()
End Using
MessageBox.Show("Result 1: " & result(0) & "; Result 2: " & result(1))
End Sub
End Class
0 내 주요 절차의 코드에서 그
진행 형태 (Form1을) 두 개의리스트 박스 (에 ListBox1과 ListBox2) 포함 :
Public Delegate Sub ShowProgressDelegate(ByVal message As String)
Public Class Form1
Public Sub AddMessage1(ByVal message As String)
If String.IsNullOrEmpty(message) Then
Exit Sub
End If
Debug.Print("out List 1: " & message)
If Me.InvokeRequired Then
Me.BeginInvoke(New ShowProgressDelegate(AddressOf Me.AddMessage1), message)
Else
Debug.Print("in List 1: " & message)
Me.ListBox1.Items.Add(message)
Me.ListBox1.SelectedIndex = Me.ListBox1.Items.Count - 1
Application.DoEvents()
End If
End Sub
Public Sub AddMessage2(ByVal message As String)
If String.IsNullOrEmpty(message) Then
Exit Sub
End If
Debug.Print("out List 2: " & message)
If Me.InvokeRequired Then
Me.BeginInvoke(New ShowProgressDelegate(AddressOf Me.AddMessage2), message)
Else
Debug.Print("in List 2: " & message)
Me.ListBox2.Items.Add(message)
Me.ListBox2.SelectedIndex = Me.ListBox2.Items.Count - 1
Application.DoEvents()
End If
End Sub
End Class
을 다음과 같이
때문에 불법 크로스 스레드 호출의 InvalidOperationException
을 피하기 위해, 나는 내 양식의 코드를 변경
디버깅 용으로 Debug.Prints를 몇 개 추가하고 InvokeRequired
부분을 추가했습니다.
이제는 두 작업이 병렬로 실행됩니다 ("out List"메시지로 Debug.Print
호출로 인해 알 수 있음)하지만 진행률 메시지가 목록 상자에 표시되지 않고 해당 코드가 실행되지 않습니다 (Debug.Print
은 " in List "메시지가 디버그 창에 표시되지 않습니다.
InvokeRequired
부분을 수행하는 데 올바른 방법으로 검색해 보았습니다. 올바른 방식으로 작동하지만 작동하지 않습니다.
누군가 나에게 말해 줄 수 있습니까? 무엇이 잘못 되었나요?
도움에 다시 한 번 감사드립니다.
태스크를 생성 할 때'TaskScheduler.FromCurrentSynchronizationContext'를 넘겨주지 않고 대신 폼의 코드에서'InvokeRequired'를 사용하면 프로그램은 아무런 진전도 보이지 않고 폼은 열리고 대기 만 보여줍니다 커서 그게 다야. 이것이 UI 스레드를 차단하지 않고 작업을 실행하는 방법에 대한 첫 번째 질문의 주제였습니다. – Nostromo
이미'BackgroundWorker'를 시도해 보았지만 실행 중이지만, 1. 'BackgroundWorker'를 사용하고 싶지 않습니다. 구성 요소이고 제대로 작동하기 위해 양식이 필요하기 때문에이 양식을 다시 사용할 수 없기 때문에 코드 및 이벤트 처리는 양식에서 발생합니다. 2. 멀티 스레딩에 대해 배우고 싶습니다. 따라서 그것이 작동하는 방식이 아니더라도 그것이 왜 작동 하는지를 이해하고 싶습니다. 두 개의'Task's를 병렬로 실행시키고 ** 진행 상황을 보여주기 위해해야 할 일이 있습니까? – Nostromo
@Nostromo - 만약 당신이'InvokeRequired' (그리고'Invoking')를 사용하고 있지만 당신의 UI 스레드가'WaitAll()'호출기 안에 앉아 있다면, 여전히 작동하지 않을 것입니다 - UI 스레드 *는 할 수 없습니다 * WaitAll() 호출 - Invoke 요청을 서비스 할 수 있어야한다. –