この問題は、UI スレッドをスリープ状態にしているために発生します。.NET 4.5 では、Task.Delay
スレッドをブロックすることなく、特定の間隔の後にのみコードを実行するために使用できます。
Dim port As New SerialPort
...
Public Async Sub SomeButton_Click()
port.WriteLine("First")
Await Task.Delay(500)
port.WriteLine("Second")
Await Task.Delay(300)
port.WriteLine("Third")
End Sub
この場合、最初のWriteLine
実行は UI スレッドで実行され、バックグラウンドで 500 ミリ秒 (実際にはタイマーを使用して) 待機が発生し、その後、元のスレッド (UI スレッド) で実行が再開され、2 番目の実行もWriteLine
UI スレッドで発生します。さらに 300 ミリ秒待機すると、UI スレッドでも 3 番目の WriteLine が発生します。
このAsync\Await
組み合わせにより、BackgroundWorker などの他のコンポーネントを使用せずに、このようなコードを非常にクリーンな方法で記述できます。また、複数の非同期呼び出しを実行するなど、バックグラウンド ワーカーではできないことも実行できます。そのような場合、複数のワーカーを使用する必要があります。ここで、もう 1 つのステートメントを記述するだけです。
このAsync Sub
構文は、イベント ハンドラーに対してのみ使用されることに注意してください。それ以外の場合はすべて、 を使用する必要がありますAsync Function SomeFunction() As Task
。
シーケンス全体をバックグラウンド スレッドで実行する場合は、Task.Run
.
Public Async Sub SomeButton_Click()
Task.Run(Async Function ()
Await SendAndWait
End Function)
End Sub
public Async Function SendAndWait As Task
_port.WriteLine("First")
Await Task.Delay(500)
_port.WriteLine("Second")
Await Task.Delay(300)
_port.WriteLine("Third")
End Function
タスクを使用する真の利点は、複数の非同期操作を組み合わせることができることです。これは、BackgroundWorker ではほぼ不可能です。この場合、非常に単純なコードを使用して、ファイルまたはデータベースからデータを非同期的に読み取り、シリアル ポートに非同期的に送信できます。
public Async Function SendAndWait(filePath As String) As Task
Dim line As String
Using reader As New StreamReader(filePath)
For i=0 To 3
line=Await reader.ReadLineAsync()
_port.WriteLine(line)
Await Task.Delay(500)
Next
End Using
End Function
プロジェクトにMicrosoft.Bcl.Asyncパッケージをasync/await
追加することで、.NET 4.0 コードでもキーワードを使用できます。