Sonhospa Ответов: 2

Замораживание пользовательского интерфейса несмотря на задачу


Привет,

используя следующий код, который в основном идентичен примеру MS, мой пользовательский интерфейс зависает, если я раскомментирую "задачу.Линия WaitAll". Разве потоки не должны обрабатываться независимо в фоновом режиме? Или команда ожидания находится не в том месте?

Спасибо за совет,
Майкл

Что я уже пробовал:

Try
    Dim tasks As New List(Of Task)()

    For Each drv In drives
        Dim currentDrive As Drive = drv
        If drv.IsReady Then
            Dim readTask As New Task(Sub()
                                         queryDrive(currentDrive)
                                     End Sub, TaskCreationOptions.LongRunning)
            tasks.Add(readTask)
            readTask.Start()
        End If
    Next

    'Task.WaitAll(tasks.ToArray())

    timerTotalMsStopwatch.Stop()
    btnGetComputers.Enabled = True
    btnCancel.Enabled = False

    Dim msg As String = String.Format("{0} files ({1:0} Sec).", files.Count, timerTotalMsStopwatch.ElapsedMilliseconds / 1000)
    SetUIText(msg, msg & vbCrLf)

Catch ex As Exception
    MsgBox(String.Format("{0}", ex.StackTrace), MsgBoxStyle.Critical, "Error")

End Try

Maciej Los

Нет, это не тождественно с примером MS. Я не вижу даже подобного решения в документации MSDN. Насколько я помню, я обеспечил вас всем необходимым. ответ на ваш предыдущий вопрос несколько ссылок.

Sonhospa

Привет еще раз, да, вы это сделали, и я посмотрел на них - стараясь не запутаться еще больше. Пожалуйста, поймите, что я новичок в этой теме! Вот пример MS, который я упомянул (извините, я не нахожу, как вставить это лучше: https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.-ctor?view=netframework-4.7.2). Они не сталкиваются с той же проблемой, что и при выводе на консоль после завершения каждой задачи.

2 Ответов

Рейтинг:
5

Richard Deeming

Как уже объяснил Дэйв, WaitAll это блокирующий вызов, который не позволит вашему потоку пользовательского интерфейса делать что-либо до тех пор, пока все задачи не будут завершены.

Самое простое решение-сделать свой метод Async, и использовать:

Await Task.WhenAll(tasks)
вместо того, чтобы Task.WaitAll(...) линия.

Асинхронное программирование с использованием Async и Await (Visual Basic) | Microsoft Docs[^]
Как расширить асинхронное пошаговое руководство с помощью задачи.WhenAll (Visual Basic) | Microsoft Docs[^]


Maciej Los

5ed!

Sonhospa

Большое тебе спасибо, Ричард! Изучив различные источники за последние выходные, я нашел именно этот метод, попробовал его и - вуаля, он работает!

Поскольку я не являюсь профессиональным программистом, для меня также было важно, где именно в моем коде я должен был его разместить. Вы не упомянули об этом, но я бы неявно понял, что нужно просто изменить свою старую линию. Кроме того, следуя другой подсказке, я вставил "readTask.GetAwaiter()" перед "readTask.Start()".

Однако спасибо, и поскольку это "недостающая часть", о которой я изначально просил, я принял ваше предложение как решение... если вы не возражаете ;-)

Рейтинг:
1

Dave Kreskowiak

WaitAll-это блокирующий вызов. Поток пользовательского интерфейса не будет делать ничего другого до тех пор, пока все задачи не будут завершены, тем самым удовлетворяя условию, которое ищет WaitAll.

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


Sonhospa

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

Dave Kreskowiak

Задачи, которые вы запустили, не находятся в потоке пользовательского интерфейса. Они вообще не вешают пользовательский интерфейс. Это призыв к WaitAll, который делает это.

Это не вопрос размещения WaitAll в правильном месте. Речь идет о том, чтобы не использовать его вообще!

Sonhospa

Да, это я понимаю. Я имею в виду, как я мог бы добиться того, чтобы мое "резюме" (количество и продолжительность) находилось в потоке пользовательского интерфейса, то есть после того, как все потоки будут закончены? Из того, что я читал, задание.WaitAll именно для этой цели... или я неправильно понял?

Dave Kreskowiak

Если вы хотите повесить свой пользовательский интерфейс на время выполнения задач, используйте WaitAll. Это блокирующий вызов, который означает, что никакой другой код в потоке WaitAll не будет выполняться до тех пор, пока он не вернется. Если вы вызовете WaitAll в потоке пользовательского интерфейса (поток, в котором запускается ваше приложение), пользовательский интерфейс вообще ничего не будет делать до тех пор, пока WaitAll не вернется и приложение не вернется в состояние ожидания. Это позволит насосу сообщений в потоке пользовательского интерфейса запускать и обрабатывать сообщения, лизать щелчки мыши и рисовать сообщения.

Если вы не хотите вешать свой пользовательский интерфейс, вам придется проявить настоящий творческий подход и не использовать ни один из методов ожидания.

Sonhospa

Я имею в виду, как я мог бы добиться того, чтобы мое "резюме" (количество и продолжительность) находилось в потоке пользовательского интерфейса, то есть после того, как все потоки будут закончены? Я уже удалил Wait, но "вы должны стать действительно творческими", я не ожидал, что в качестве совета и возможного решения на этом форуме. Но все равно спасибо.

Dave Kreskowiak

Я уже говорил вам об одном возможном решении.

Sonhospa

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

Dave Kreskowiak

Итак, каково ваше представление о помощи? Код написан для вас? Извините, но это не произойдет прямо сейчас, когда я печатаю это дерьмо на своем телефоне, сидя в приемной больницы.

Мир вышел. С меня хватит.

Sonhospa

Извините за больничную историю, я искренне надеюсь, что ничего серьезного и все получится хорошо! Только не позволяйте им давать вам что-нибудь на латыни, это было бы бесполезно, если бы вы не изучали ее.

К вашему сведению: я собираюсь следовать подсказке другого потока форумов, где "Task.Result" хранится в переменной. Мир!

Maciej Los

5ed!