асинхронные потоки и анонимные делегаты

#wpf #vb.net #visual-studio-2008 #asynchronous #anonymous-types

#wpf #vb.net #visual-studio-2008 #асинхронный #анонимные типы

Вопрос:

Хорошо, теперь я могу использовать 2 метода для запуска своих потоков: Dispatcher и BackgroundWorker.

Диспетчер:

 ' I launch the asynchronous process
Dim a As New Action(AddressOf operazioneLunga)
a.BeginInvoke(Nothing, Nothing)

' I update the GUI passing some parameters
Dim a As New Action(Of Integer, String)(AddressOf aggiorna_UI)
Me.Dispatcher.BeginInvoke(DispatcherPriority.Normal, a, 5, "pippo")
  

BackgroundWorker:

 Private bw As BackgroundWorker = Nothing

Private Sub initial()
  bw = New BackgroundWorker
  AddHandler bw.DoWork, AddressOf longOp
  AddHandler bw.RunWorkerCompleted, AddressOf endBGW
  bw.RunWorkerAsync ()
End Sub

Private Sub longOp(ByVal sender As Object, ByVal e As DoWorkEventArgs)
  Dim l As List(Of miaClasse2) = <Long Operation ...>

  e.Result = l
End Sub

Private Sub endBGW(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
  Dim l As List(Of miaClasse2) = e.Result
  Dim be As BindingExpression = BindingOperations.GetBindingExpression(mioDatagrid, DataGrid.ItemsSourceProperty)
  Dim m As miaClasse1 = DirectCast(be.DataItem, miaClasse1)
  m.GetData (l)
  mioDatagrid.UpdateLayout()
  mioDatagrid.ScrollIntoView (mioDatagrid.Items(0))
  RemoveHandler bw.DoWork, AddressOf massiccia
  RemoveHandler bw.RunWorkerCompleted, AddressOf fineBGW
  bw.Dispose()
End Sub
  

Я не знаю, что лучше, но я думаю, что использую BackgroundWorker, потому что, я полагаю, есть другие аргументы о Dispatcher, которые я должен знать, и я не чувствую себя в безопасности.

Pileggi

Мой предыдущий пост:

Всем привет!

Мое приложение находится в WPF / Vb framework 3.5 SP1. Мне нужно выполнить некоторые методы в асинхронных потоках. Я знаю этот способ:

 Private Delegate Sub dMassiccia()
Private Delegate Sub dAggiornaUI()

Private Sub iniziale()
  Dim massicciaTemp As New dMassiccia(AddressOf massiccia)
  massicciaTemp.BeginInvoke(Nothing, Nothing)
End Sub

Private Sub massiccia()
  'long operations...
  Me.Dispatcher.BeginInvoke(DispatcherPriority.Normal, _
    New dAggiornaUI(AddressOf aggiornaUI))
End Sub

Private Sub aggiornaUI()
  'update the UI...
End Sub
  

Но таким образом я должен объявлять делегата для каждого mothod, который я хочу запустить в асинхронном потоке, и это очень неудобно. У меня есть много методов для запуска таким образом. Я знаю, что существуют анонимные делегаты, но я не знаю, как их использовать в этом случае.
Можете ли вы мне помочь?
Pileggi

PS. Другая информация: в данный момент мне не нужно просматривать статус процесса, запущенного в асинхронном потоке. Длительные операции — это некоторые запросы к веб-сервису, которые каждый раз могут занимать несколько секунд. С количеством потоков проблем нет, потому что я ограничиваю возможности пользователя запускать новые потоки до тех пор, пока один из них не будет завершен. Мне нужны асинхронные потоки, среди прочих причин, потому что я не хочу блокировать приложение, я хочу заменить курсор мыши пользовательским элементом управления и т.д..

Ответ №1:

Что вы пытаетесь сделать, что требует от вас запуска всех этих потоков? Похоже, вы создаете вторичный поток только для того, чтобы иметь возможность выполнять обновления графического интерфейса.

Прежде всего, если вам нужно создать много потоков, то вы рискуете довольно быстро исчерпать доступные потоки. Я думал, что максимальное значение составляет всего 64, но в документации указано 250 на процесс, и оно также настраивается через GetMaxThreads и SetMaxThreads . В любом случае, вам нужно решить, подходит ли вам использование потоков ThreadPool (которые используются при использовании BeginInvoke / EndInvoke).

Сколько времени занимает обновление вашего графического интерфейса? Будут ли они выполняться в течение всего срока действия вашего приложения? Можете ли вы вместо этого использовать обычный поток? Рассмотрите возможность использования a BackgroundWorker для обновления графического интерфейса, если вам просто нужно периодически обновлять информацию о состоянии. В некоторых случаях даже DispatcherTimer может сработать. Это просто зависит от того, что вы хотите сделать.

Вы также не показываете весь свой код, но в том, что опубликовано, EndInvoke не вызывается. Если вы сделаете это и в конечном итоге выдадите исключение, вы не сможете перехватить его и обработать ошибку должным образом.

Комментарии:

1. @Dave: Большое вам спасибо за проявленный интерес. Я отредактировал свой пост, добавив ответы на ваши вопросы. Моя единственная проблема в том, что я хотел бы использовать анонимный делегат для написания меньшего количества кода, но я не знаю как.

2. Что ж, тогда я бы рекомендовал выполнить поиск. 🙂 Я недостаточно эксперт в этой области, чтобы сказать вам, как вы должны это делать. Когда я использую делегаты, я делаю это так же, как и вы — создаю делегат и передаю его конструктору функцию, которую я хочу выполнить в потоке. Я не вижу в этом ничего плохого. Единственное, что вызывает у меня удивление, это метод, с помощью которого вы выполняете обновления графического интерфейса, что кажется немного странным. Вы должны увидеть, что другие публикуют относительно этого подхода.

3. @pileggi Просто потому, что вы запускаете поток, который выполняет длинный набор операций, а затем запускаете другой поток для обновления графического интерфейса. Графический интерфейс может быть обновлен только из основного потока, поэтому похоже, что вы используете все, что кажется удобным для доступа к диспетчеру. Существуют другие способы обновления графического интерфейса пользователя из потоков, например BackgroundWorker . Или вы можете поместить свои результаты в общую память и периодически обновлять свой графический интерфейс, считывая общую память. Память должна быть защищена критическим разделом, но вы всегда можете использовать ReaderWriterLockSlim для повышения производительности.

4. @Dave: спасибо. Я вижу, вы очень компетентны в моделях потоков. В прошлом я использовал BackgroundWorker, но теперь я вижу, что мне нужно немного изучить, прежде чем писать больше кода. Я просто спрашиваю вас вот о чем: когда я найду решение, могу ли я найти вас снова, чтобы узнать ваше мнение? Я говорю вам это, потому что этот форум замечательный, но если вы потратите слишком много времени на следующий пост, будет трудно найти того, кто ответит.

5. @pileggi конечно, просто опубликуйте обновление этого вопроса. Только потому, что я заметил несколько вещей, пожалуйста, не думайте, что я компетентен . Я постоянно совершаю много ошибок. Со временем я постепенно совершенствуюсь. 🙂