2011-04-24 9 views
5

이것은 네트워크 데이터를 받고 GUI (대화 상자, 양식 등)에서 사용하기 위해 수년 동안 사용해 왔던 기술입니다.스레드에서 실시간 Gui 업데이트 속도 향상

public delegate void mydelegate(Byte[] message); 

    public ReceiveEngineCS(String LocalIpIn, String ReceiveFromIp, mydelegate d) 
    { 
     this.m_LocalIpIn = LocalIpIn; 
     this.m_ReceiveFromIp = ReceiveFromIp; 
     m_MainCallback = d; 
     SetupReceive(); 
     m_Running = true; 
     //Create the Track receive thread and pass the parent (this) 
     m_RtdirReceiveThread = new Thread(new ParameterizedThreadStart(MessageRecieveThread)); 
     m_RtdirReceiveThread.Start(this); 
    } 

    private void MessageRecieveThread(System.Object obj) 
    { 
     ReceiveEngineCS parent = (ReceiveEngineCS)obj; 

     while(parent.m_Running) 
     { 
       Byte[] receiveBytes = new Byte[1500]; 
       try 
       { 
        receiveBytes = parent.m_ClientReceiver.Receive(ref parent.ipEndPoint); 
        parent.ThreadOutput(receiveBytes); 
       } 
       catch (Exception e) 
       { 
        parent.StatusUpdate(e.ToString()); 
       }       
     }   
    } 

    public void ThreadOutput(Byte[] message) 
    { 
     m_MainCallback(message);   
    } 

public partial class SystemMain : Form 
{ 
    //Local Class Variables 
    Network.ReceiveEngineCS SystemMessageReceiver; 
    private void Form1_Load(object sender, EventArgs e) 
    { 
     //Load up the message receiver 
     SystemMessageReceiver = new Network.ReceiveEngineCS(localAddy, fromAddy, new mydelegate(LocalDelegate)); 
    } 

    public void LocalDelegate(Byte[] message) 
    { 
     if (Form.ListView.InvokeRequired) 
     { 
      //External call: invoke delegate 
      Form.ListView.Invoke(new mydelegate(this.LocalDelegate), message); 
     } 
     else 
     { 
      //Get the Packet Header 
      Formats.PacketHeaderObject ph = new Formats.PacketHeaderObject(message); 
      //Update or Add item to Specific ListView 
      ... update views 
     } 
    } 
} 

수신자는 10에서 100 사이의 실시간 메시지를 초당 또는 더 자주 가져옵니다.

저는 최근에 .Net 4.0과 C#으로 연구를 해오 고 있으며, 작업자 스레드와 같은 데이터 처리 과 같은 많은 다른 유사한 방법과 Delegate와 Invoke를 사용하는 다른 방법을 발견했습니다.

내 질문 ...이 데이터 수신/GUI 업데이트를 수행하는 최신 .Net 라이브러리 (3.5, 4.0 등)에서보다 효율적인 방법이 있습니까?

이 방법이 C#에서도 잘 작동하지 않는다고 생각합니다.

도움을 주시면 감사하겠습니다.

+1

사용자에게 초당 100 통의 알림을 던지는 것은별로 의미가 없습니다. 흐림처럼 보일 것입니다. 먼저 UI를 사용 가능하게 만들고 문제를 해결하십시오. Winforms에 변경 사항이 없습니다. –

+0

멋진 아이디어 Hans. 스레드에 들어오는 데이터에 대한 메타 데이터를 작성하고 GUI를 매 초만 업데이트하면 Gui가 업데이트로 인해 수렁에 빠지게하면서 데이터에 대한 적절한 사용자 응답을 제공 할 수 있습니다. 일반적으로 운영자는 업데이트 된 데이터 항목의 대략적인 개수를 데이터 속도에 대한 지침으로 사용합니다. 따라서 10 초를 한눈에 50 초로 계산합니다.하지만 메타 업데이트로 통합하여 목록보기에 추가 할 수 있습니다. – Sleff

답변

4

GUI에 업데이트를 게시하는 가장 좋은 방법 중 하나는 업데이트에 포함 된 데이터를 작업자 스레드 패키지로 묶어서 대기열에 넣는 것입니다. 그런 다음 UI 스레드는 큐를 주기적으로 폴링합니다. 작업자 스레드가 Control.Invoke을 사용하여 UI를 업데이트하는 것은 방법은 제 의견으로 남용됩니다. 대조적으로 업데이트에 대한 UI 스레드 폴링을 사용하면 몇 가지 이점이 있습니다.

  • Control.Invoke이 부과하는 UI와 작업자 스레드 간의 긴밀한 연결이 끊어집니다.
  • 어쨌든 속해야하는 UI 스레드에서 UI 스레드를 업데이트해야합니다.
  • UI 스레드는 업데이트가 필요한시기와 빈도를 지정합니다.
  • 작업자 스레드에서 시작된 마샬링 기술의 경우처럼 UI 메시지 펌프가 오버런 될 위험이 없습니다.
  • 작업자 스레드는 다음 단계를 진행하기 전에 업데이트가 수행되었음을 확인하는 것을 기다릴 필요가 없습니다 (즉, UI와 작업자 스레드 모두에서 더 많은 처리량을 얻음).

ThreadOutput이 구현 된 방법에 대해서는 언급하지 않았지만, 위에서 언급 한 방법을 고려해 볼 수 있습니다. 경험은 이것이 일반적으로 최선의 방법이라고 가르쳐 왔습니다. UI 스레드가 업데이트주기를 조절하도록하는 것이 큰 이점입니다.

+0

공유 리소스에서 데이터를 폴링 할 때 항상 겪었던 문제는 타이밍 중 하나였습니다.공유 대기열을 잠 그거나 잠금 해제하면 많은 오버 헤드가 발생합니다 (당장 문제가 발생하지는 않습니다). 작업자 스레드를 살펴본 결과 스레드가 업데이트를 다시 전송하는 메커니즘이 있음을 확인했습니다. 내가 확신하지 못했던 것은 UI 소유 큐를 업데이트하기 위해 작업 스레드에 대한 호출을 사용해야하는지 여부입니다. – Sleff

+0

대기열을 잠그는 것은 매우 비싼 작업 인'Control.Invoke'와 비교하면 아무 것도 아닙니다. 게다가, 당신은 항상 잠금없는 메커니즘을 사용하는'ConcurrentQueue'를 사용할 수 있습니다. 작업자 스레드는 대기열에 무언가를 게시하기 위해'Invoke '를 사용할 필요가 없습니다. 처음에는 UI 소유 대기열이라고 부르는 것이 다소 잘못된 것일 수 있습니다. –

+0

그건 @ 브라이언을 돕는다. 나는 invoke의 비용을 확신하지 못했습니다. 나는 항상 단순한 파일이나 저속의 xml 데이터로부터 gui를 갱신하는 간단한 예제에 사용되는 것을 보았습니다. ConcurrentQueue를 확인하고 @Hans가 제안한대로 업데이트해야 할 부분을 줄이는 방법을 살펴 보겠습니다. – Sleff

1

매번 새 스레드를 돌리는 대신 Thread Pooling을 살펴보십시오.

+0

감사합니다 Zamboni하지만 실제로는 메시지의 스레드를 하나만 사용하여 앱의 전체 수명을 수신합니다. 메시지는 항상 수신해야하는 이벤트의 지속적인 업데이트입니다. – Sleff