Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
С помощью Task.WhenAnyможно одновременно запускать несколько задач и обрабатывать их по одному, а не обрабатывать их в том порядке, в котором они запущены.
В следующем примере используется запрос для создания коллекции задач. Каждая задача скачивает содержимое указанного веб-сайта. В каждой итерации цикла во время ожидания вызов WhenAny
возвращает задачу в коллекции задач, завершающих загрузку первым. Эта задача удаляется из коллекции и затем обрабатывается. Цикл повторяется, пока коллекция не содержит больше задач.
Замечание
Для выполнения примеров необходимо установить Visual Studio 2012 или более поздней версии и .NET Framework 4.5 или более поздней версии на компьютере.
Скачивание примера
Вы можете скачать полный проект Windows Presentation Foundation (WPF) из примера Async: настройки вашего приложения и затем выполните следующие действия.
Распакуйте скачанный файл и запустите Visual Studio.
В строке меню выберите "Файл", "Открыть", "Проект или решение".
В диалоговом окне "Открыть проект" откройте папку, содержащую пример кода, который вы распаковали, а затем откройте файл решения (.sln) для AsyncFineTuningVB.
В обозревателе решений откройте контекстное меню для проекта ProcessTasksAsTheyFinish , а затем выберите "Задать в качестве проекта запуска".
Выберите клавишу F5 для запуска проекта.
Выберите клавиши CTRL+F5, чтобы запустить проект без отладки.
Запустите проект несколько раз, чтобы убедиться, что скачанные длины не всегда отображаются в одном порядке.
Если вы не хотите скачать проект, просмотрите файл MainWindow.xaml.vb в конце этого раздела.
Создание примера
В этом примере добавляется код к разработанному в разделе "Отмена оставшихся асинхронных задач после завершения одной задачи (Visual Basic)" и используется тот же пользовательский интерфейс.
Чтобы создать пример самостоятельно, следуйте пошаговым инструкциям в разделе "Загрузка примера", но выберите CancelAfterOneTask в качестве StartUp Project. Добавьте изменения в данную тему в метод AccessTheWebAsync
в этом проекте. Изменения отмечены звездочками.
Проект CancelAfterOneTask уже содержит запрос, который при выполнении создает коллекцию задач. Каждый вызов ProcessURLAsync
в следующем коде возвращает Task<TResult>, где TResult
является целым числом.
Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
From url In urlList Select ProcessURLAsync(url, client, ct)
В файле MainWindow.xaml.vb проекта внесите следующие изменения в AccessTheWebAsync
метод.
Выполните запрос, применяя Enumerable.ToList вместо ToArray.
Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()
Добавьте цикл while, выполняющий следующие действия для каждой задачи в коллекции.
Ожидает вызова
WhenAny
, чтобы выявить первую задачу в коллекции, завершающую загрузку.Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)
Удаляет эту задачу из коллекции.
downloadTasks.Remove(finishedTask)
Ожидается
finishedTask
, который возвращается при вызове функцииProcessURLAsync
. ПеременнаяfinishedTask
— это Task<TResult>, гдеTReturn
— целое число. Задача уже завершена, но вы ожидаете получения длины загружаемого веб-сайта, как показано в следующем примере.Dim length = Await finishedTask resultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded website: {0}" & vbCrLf, length)
Проект следует запустить несколько раз, чтобы убедиться, что скачанные длины не всегда отображаются в одном порядке.
Осторожность
Вы можете использовать цикл WhenAny
, как описано в примере, для решения проблем, связанных с небольшим количеством задач. Однако другие подходы более эффективны при наличии большого количества задач для обработки. Дополнительные сведения и примеры см. в разделе "Обработка задач по мере их выполнения".
Полный пример
Следующий код представляет собой полный текст файла MainWindow.xaml.vb для примера. Звездочки помечают элементы, добавленные в этот пример.
Обратите внимание, что необходимо добавить ссылку для System.Net.Http.
Проект можно скачать из примера Async: тонкая настройка вашего приложения.
' Add an Imports directive and a reference for System.Net.Http.
Imports System.Net.Http
' Add the following Imports directive for System.Threading.
Imports System.Threading
Class MainWindow
' Declare a System.Threading.CancellationTokenSource.
Dim cts As CancellationTokenSource
Private Async Sub startButton_Click(sender As Object, e As RoutedEventArgs)
' Instantiate the CancellationTokenSource.
cts = New CancellationTokenSource()
resultsTextBox.Clear()
Try
Await AccessTheWebAsync(cts.Token)
resultsTextBox.Text &= vbCrLf & "Downloads complete."
Catch ex As OperationCanceledException
resultsTextBox.Text &= vbCrLf & "Downloads canceled." & vbCrLf
Catch ex As Exception
resultsTextBox.Text &= vbCrLf & "Downloads failed." & vbCrLf
End Try
' Set the CancellationTokenSource to Nothing when the download is complete.
cts = Nothing
End Sub
' You can still include a Cancel button if you want to.
Private Sub cancelButton_Click(sender As Object, e As RoutedEventArgs)
If cts IsNot Nothing Then
cts.Cancel()
End If
End Sub
' Provide a parameter for the CancellationToken.
' Change the return type to Task because the method has no return statement.
Async Function AccessTheWebAsync(ct As CancellationToken) As Task
Dim client As HttpClient = New HttpClient()
' Call SetUpURLList to make a list of web addresses.
Dim urlList As List(Of String) = SetUpURLList()
' ***Create a query that, when executed, returns a collection of tasks.
Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
From url In urlList Select ProcessURLAsync(url, client, ct)
' ***Use ToList to execute the query and start the download tasks.
Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()
' ***Add a loop to process the tasks one at a time until none remain.
While downloadTasks.Count > 0
' ***Identify the first task that completes.
Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)
' ***Remove the selected task from the list so that you don't
' process it more than once.
downloadTasks.Remove(finishedTask)
' ***Await the first completed task and display the results.
Dim length = Await finishedTask
resultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded website: {0}" & vbCrLf, length)
End While
End Function
' Bundle the processing steps for a website into one async method.
Async Function ProcessURLAsync(url As String, client As HttpClient, ct As CancellationToken) As Task(Of Integer)
' GetAsync returns a Task(Of HttpResponseMessage).
Dim response As HttpResponseMessage = Await client.GetAsync(url, ct)
' Retrieve the website contents from the HttpResponseMessage.
Dim urlContents As Byte() = Await response.Content.ReadAsByteArrayAsync()
Return urlContents.Length
End Function
' Add a method that creates a list of web addresses.
Private Function SetUpURLList() As List(Of String)
Dim urls = New List(Of String) From
{
"https://msdn.microsoft.com",
"https://msdn.microsoft.com/library/hh290138.aspx",
"https://msdn.microsoft.com/library/hh290140.aspx",
"https://msdn.microsoft.com/library/dd470362.aspx",
"https://msdn.microsoft.com/library/aa578028.aspx",
"https://msdn.microsoft.com/library/ms404677.aspx",
"https://msdn.microsoft.com/library/ff730837.aspx"
}
Return urls
End Function
End Class
' Sample output:
' Length of the download: 226093
' Length of the download: 412588
' Length of the download: 175490
' Length of the download: 204890
' Length of the download: 158855
' Length of the download: 145790
' Length of the download: 44908
' Downloads complete.