2012-05-08 9 views
5

Jestem zdezorientowany scenariuszem, który napotkałem podczas dostępu do wątków. Oto, co próbuję zrobić:BeginInvoke blokuje interfejs użytkownika, podczas gdy Invoke nie jest.!

Main UI wątek - pozycja menu kliknij tworzę tle Pracownik i uruchomić go asynchronicznie

private void actionSubMenuItem_Click(object sender, EventArgs e) 
{ 
     ToolStripMenuItem itemSelected = (ToolStripMenuItem)sender; 
     ExecuteTheActionSelected(itemSelected.Text); 
} 

Sposób ExecuteTheActionSelected się następująco:

private void ExecuteTheActionSelected(string actionSelected) 
{ 
     BackgroundWorker localBackgroundWorker = new BackgroundWorker(); 
     localBackgroundWorker.DoWork += new DoWorkEventHandler(localBackgroundWorker_DoWork); 
     localBackgroundWorker.RunWorkerAsync(SynchronizationContext.Current); 
} 

Model localBackgroundWorker_DoWork ma:

ActionExecutionHelper actionExecutioner = new ActionExecutionHelper() 
actionExecutioner.Execute(); 

The Execute metoda w tej klasie, która ma metody wywołującego które rzeczywiście wywołuje procedurę obsługi zdarzeń w wątku UI:

public void Execute() 
{ 
     // ---- CODE ----- 
     new MethodInvoker(ReadStdOut).BeginInvoke(null, null); 
} 

protected virtual void ReadStdOut() 
{ 
     string str; 
     while ((str = executionProcess.StandardOutput.ReadLine()) != null) 
     { 
      object sender = new object(); 
      DataReceivedEventArgs e = new DataReceivedEventArgs(str); 
      outputDataReceived.Invoke(sender, e); 
      //This delegate invokes UI event handler 
     } 
} 

obsługi zdarzenia UI jest następująca:

private void executionProcess_OutputDataReceived(object sender, DataReceivedEventArgs e) 
{ 
    if (_dwExecuteAction != null) 
    { 
     _dwExecuteAction.ShowDataInExecutionWindow(e.Text); 
    } 
} 

Teraz Nadchodzi przekrój problem wątek :

public void ShowDataInExecutionWindow(string message) 
{ 
    if (rchtxtExecutionResults.InvokeRequired) 
    { 
      rchtxtExecutionResults.Invoke(new ShowDataExecutionDelegate(ShowDataInExecutionWindow), message); 
    } 
    else 
    { 
      this.rchtxtExecutionResults.AppendText(message + Environment.NewLine); 
    } 
} 

Tutaj Invoke nie blokuje UI gdzie jak BeginInvoke bloków. Proszę, pomóżcie mi zrozumieć ten scenariusz, ponieważ jestem bardzo zdezorientowany.

+0

Obawiam się, że nie znam odpowiedzi, ale podejście, które podjąłbym, aby ją znaleźć, polegałoby na sprawdzeniu, w jaki sposób wielopoziomowe poziomy inwokacji i pracownicy pracujący w tle wchodzą ze sobą w interakcje i gdzie wszystko faktycznie jest wykonywane, więc że rozumiesz, jak wszystko pasuje do siebie. –

Odpowiedz

6

Tak, to normalne. Korzyści można uzyskać z Invoke() jest to, że bloki nitka pracownik. Podczas używania BeginInvoke() wątek utrzymuje motoryzację i wywołuje żądania z szybkością wyższą niż wątek interfejsu użytkownika może obsłużyć. Zależy to od tego, o co prosisz wątek interfejsu użytkownika, ale zaczyna się on stać problemem około 1000 wywołań na sekundę.

wątku UI przestaje być czuły w tym scenariuszu jest stale znalezienie innego żądania invoke z powrotem, podczas gdy pompuje pętlę komunikatów i nie ominąć robi swoje zwykłe obowiązki już. Żądania wprowadzania i malowania nie są przetwarzane.

Oczywistym źródłem problemu jest żądanie wywołania pod każdej linii z danych wyjściowych pobranych z procesu. Generuje je zbyt szybko. Musisz to naprawić, obniżając stawkę, z którą się powołujesz. Jest na to prosta zasada, próbujesz tylko zająć człowieka zajętego, wywołując ponad 25 razy na sekundę to, co produkujesz, ale rozmycie na oko. Tak więc buforuj linie i mierz czas, jaki minął od ostatniego wywołania invoke.

Należy również pamiętać, że za pomocą Invoke() jest proste obejście, ale to nie jest dokładnie to gwarantowane do pracy. Jest to wyścig, nitka pracownik może potencjalnie zawsze zadzwonić następnego Invoke() odrobinę wcześniej niż w głównym wątku ponownego wprowadzania do pętli wiadomości i czytając następną wiadomość. W takim przypadku nadal będziesz mieć dokładnie ten sam problem.

+0

Dobrze, że daje wyjaśnienie "BeginInvoke()" blokowanie interfejsu użytkownika. Ale dlaczego 'Invoke()' nie blokuje wątku UI?Mogę łatwo uzyskać dostęp do innych formantów, gdy używam 'Invoke()' –

+0

Ponieważ blokuje to wątek roboczy, więc nie może tak często zatrzasnąć wątku UI z żądaniami wywołania. Kluczowym punktem jest to, że wątek UI nie jest faktycznie zablokowany, po prostu nie zajmuje się wszystkimi normalnymi obowiązkami. –

+0

Jeszcze jedno pytanie !! Jak mógł wiedzieć o takich drobnych rzeczach? :) Człowiek, który wymaga więcej głębokiej wiedzy na temat tego, co odkrywasz. Przeszukałem wiele stron, ale nigdy nie doszłoby do takiego wniosku! –

Powiązane problemy