2014-11-26 2 views
0

시리얼 통신을 수행하는 프로그램이 있습니다. 명령을 보낸 후 프로그램은 데이터 수신을 잠깐 동안 기다려야합니다. 데이터를 수신한다 (노드 1)VB.NET의 GUI 지연

슬립 (500에게) '

데이터를 전송

timer_tick : 데이터는 액티브 MSCOMM가

http://msdn.microsoft.com/en-us/library/aa259393%28v=vs.60%29.aspx

psuedocode 이런 생겼다하여 수신 한편, 노드 1

데이터 전송 (노드 2)

. . .

문제는 sleep로 인해 GUI가 지연되는 것입니다. 몇 가지 대안을 생각했습니다

1) 타이머에 인공 카운터를 사용하여 다음 명령을 보내기 전에 500ms를 대략적으로 사용하지만 나에게 매우 좋은 생각처럼 보이지 않습니다. 2) 타이머 대신 스레드 사용 ? 및 application.doevents을 활용 백그라운드 스레드

http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground(v=vs.71).aspx

3)로 설정?

나는 옵션 2 또는 3에 익숙하지 않으므로 필자는 코드를 복잡하게 만드는 요소를 소개하는 것을 주저합니다. 아무도이 문제에 더 잘 맞는 대안을 조언하거나 옵션 2 또는 3을 향해 일하기 시작할 수 있습니까?

+1

단순히 작업자 스레드에서이 작업을 수행하지 않는 이유는 무엇입니까? –

+0

좋아, 나는 그 위에있다! 감사! – KRC

+2

왜 .NET의 [SerialPort] (http://msdn.microsoft.com/en-us/library/system.io.ports.serialport%28v=vs.110%29.aspx) 대신 COM 구성 요소를 사용하고 있습니까? ? 또한 응답을받을 수 있도록 기다리고 계십니까? 응답이 500ms 전에 수신 된 경우 두 번째 명령을 먼저 보내면 괜찮습니까? –

답변

2

문제는 사용자의 timer이 UI 스레드에서 실행 중이므로 해당 서브 루틴에서 sleep 일 때 UI 스레드 (따라서 '지연')를 잠자고있는 것이 문제입니다. 옵션을 이해하는 것이 아마 가장 쉽다 최고의

는 폼에 BackgroundWorker 컨트롤을 추가하고 UI 스레드를 차단하지 않습니다 근로자 DoWork 루틴으로 전송 (수면) 코드를 이동하는 것입니다. 이 같은

뭔가 :

Worker_DoWork 
    send data (node 1) 
    sleep(500) 'receives data for node 1 meanwhile 
    send data (node 2) 
End Sub 

DoEvents의 사용은 권장하지 강하게입니다 - .NET이 사용에 대한 매우 몇 가지 이유가있다 당신이 UI 스레드를 가하고 있습니다 때문에 문제가 발생

+0

Tasks 및 Task.Delay를 사용할 수있을 때 BackgroundWorker 또는 Thread.Sleep을 사용할 필요가 없으므로 완전히 차단되지 않습니다. –

+0

당신이 생각하는 것이 아닙니다. 그것은 아무것도 자지 않습니다. 백그라운드 타이머를 시작하고, 원래 스레드를 해제하고, 타이머가 시작되면 픽업합니다. 어떤 쓰레드도 사용하거나 쓰지 않습니다. –

+0

또한, '비동기/대기'작업은 모든 경우에 BackgroundWorker보다 쉽고 간단합니다. [Stephen Cleary] (http://blog.stephencleary.com/2013/05/taskrun-vs-backgroundworker-intro.html)는 BackgroundWorker의 기능에 대한 모든 대안을 표시하는 철저한 일련의 게시물과 ' t 표지,보고 진행 메시지와 같습니다. –

2

자다. .NET 4.5에서, 당신은 어떤 스레드를 차단하지 않고 코드가 특정 간격 이후에만 실행할 수 있도록 Task.Delay을 사용할 수 있습니다, 예를 들면 : 첫 번째 WriteLine는 UI 스레드에서 실행이 경우

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 

은 대기가 발생 배경을 500ms (실제 타이머 사용)로 설정하면 원래 스레드 (UI 스레드)에서 실행이 다시 시작되고 두 번째 WriteLine이 UI 스레드에서도 발생합니다. 또 300ms 기다린 다음 세 번째 WriteLine이 UI 스레드에서도 발생합니다.

Async\Await 조합을 사용하면 BackgroundWorker와 같은 다른 구성 요소를 사용하지 않고도 코드를 매우 명확하게 작성할 수 있습니다. 또한 여러 비동기 호출을 실행하는 것처럼 백그라운드 작업자가 수행 할 수없는 작업을 수행 할 수도 있습니다. 이 경우 복수의 작업자가 필요합니다. 이제는 하나 이상의 문을 작성하십시오.

구문은 이벤트 처리기에만 사용됩니다. 다른 모든 경우에는 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 

Tasks를 사용하여 얻는 진정한 이점은 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 

당신은 .NET에서 async/await 키워드를 사용할 수 있습니다 4.0 코드뿐만 아니라 프로젝트에 Microsoft.Bcl.Async 패키지를 추가하십시오.

+1

.NET 4.5를 사용하지 않으므로 BackgroundWorker 만 사용할 수 있습니다. 하지만 다른 대안을 내게 경고 해 주셔서 고맙습니다. 언젠가는 최신 버전의 .NET에서 작업해야합니다. – KRC

+0

4.0에서도이 모든 것을 사용할 수 있습니다. 작업은 .NET 4.0에서 추가되었으며 [Microsoft.Bcl.Async] (https://www.nuget.org/packages/Microsoft.Bcl.Async) 패키지는 Visual Studio 2012 용 4.0에 'async/await'에 대한 지원을 추가합니다 +. VS 2010을 사용하는 경우에도 무료 Visual Studio 2013 Pro (미안 "커뮤니티") 버전 –

+0

으로 업그레이드 할 수 있습니다. 1.1.><그러나 도움이되어 주셔서 감사합니다! – KRC