Знаете ли вы, откуда это расхождение?Как бы вы решили это?
Я не уверен.Я не вижу в вашем коде ничего очевидного, что могло бы вызвать разницу между Mono и .NET.Если бы мне пришлось делать дикие предположения, я бы сказал, что есть вероятность, что вы наткнулись на неясную ошибку в Mono.Хотя, я полагаю, возможно, что Mono использует достаточно другой механизм для обработки сообщений WM_PAINT, которые приводят к обновлению формы.Постоянный стук потока пользовательского интерфейса от повторных вызовов к Invoke
может нарушать способность Моно обновлять форму.
И, наконец, почему здесь не работает BeginInvoke?
Вызов Invoke
в узком цикле достаточно плох, но BeginInvoke
будет еще хуже.Рабочий поток загружает насос сообщений пользовательского интерфейса.BeginInvoke
не ожидает, пока поток пользовательского интерфейса завершит выполнение делегата.Он просто отправляет запросы и быстро возвращается.Вот почему, кажется, висит.Сообщения, которые BeginInvoke
отправляет в очередь сообщений пользовательского интерфейса, продолжают накапливаться, так как рабочий поток, вероятно, серьезно перебивает способность потока пользовательского интерфейса обрабатывать их.
Другие комментарии
Я должен также упомянуть, что рабочий поток почти бесполезен в коде.Причина в том, что у вас есть вызов Invoke
на каждой итерации.Invoke
блокируется до тех пор, пока пользовательский интерфейс не завершит выполнение делегата.Это означает, что ваш рабочий поток и поток пользовательского интерфейса, по сути, находятся в состоянии блокировки друг с другом.Другими словами, работник тратит большую часть своего времени на ожидание пользовательского интерфейса и наоборот.
Решение
Одним из возможных решений является замедление скорости, с которойInvoke
называется.Вместо того, чтобы вызывать его на каждой итерации цикла, попробуйте делать это каждые 1000 итераций или тому подобное.
Любой, даже лучший, подход состоит в том, чтобы вообще не использовать Invoke
или BeginInvoke
.Лично я думаю, что эти механизмы для обновления пользовательского интерфейса слишком перегружены.Почти всегда лучше позволить потоку пользовательского интерфейса регулировать собственную частоту обновления, особенно когда рабочий поток выполняет непрерывную обработку.Это означает, что вам нужно будет поместить таймер в форму и установить желаемую частоту обновления.Из события Tick
вы будете проверять общую структуру данных, которую обновляет рабочий поток, и использовать эту информацию для обновления элементов управления в форме.Это имеет несколько преимуществ.
- Это нарушает тесную связь между пользовательским интерфейсом и рабочими потоками, которые навязывает
Control.Invoke
. - Это возлагает ответственность за обновление потока пользовательского интерфейса на поток пользовательского интерфейса.где он должен находиться в любом случае.
- Поток пользовательского интерфейса должен определять, когда и как часто должно происходить обновление.
- Нет риска переполнения насоса сообщений пользовательского интерфейса, как в случаес методами маршалинга, инициированными рабочим потоком.
- Рабочему потоку не нужно ждать подтверждения того, что обновление было выполнено, прежде чем переходить к следующим шагам (т. е. вы получаете большую пропускную способность как в пользовательском интерфейсе, так и врабочие темы).