Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Используя метод Task.WhenAny вместе с CancellationToken, можно отменить все оставшиеся задачи при завершении одной из них. Метод WhenAny принимает аргумент, который представляет собой коллекцию задач. Метод запускает все задачи и возвращает одну задачу. Одна задача завершается после завершения любой задачи в коллекции.
В этом примере показано, как использовать маркер отмены в сочетании с WhenAny для удержания первой из завершившихся задач из коллекции задач и отмены оставшихся. Каждая задача загружает содержимое веб-сайта. В примере отображается длина содержимого для завершения первого скачивания, и отменяются другие загрузки.
Замечание
Для выполнения примеров необходимо установить Visual Studio 2012 или более поздней версии и .NET Framework 4.5 или более поздней версии на компьютере.
Скачивание примера
Вы можете скачать полный проект Windows Presentation Foundation (WPF) из примера Async: настройки вашего приложения и затем выполните следующие действия.
Распакуйте скачанный файл и запустите Visual Studio.
В строке меню выберите "Файл", "Открыть", "Проект или решение".
В диалоговом окне "Открыть проект" откройте папку, содержащую пример кода, который вы распаковали, а затем откройте файл решения (.sln) для AsyncFineTuningVB.
В обозревателе решений откройте контекстное меню проекта CancelAfterOneTask , а затем выберите "Задать в качестве проекта запуска".
Выберите клавишу F5 для запуска проекта.
Выберите клавиши CTRL+F5, чтобы запустить проект без отладки.
Запустите программу несколько раз, чтобы убедиться, какая из загрузок завершается первой.
Если вы не хотите скачать проект, просмотрите файл MainWindow.xaml.vb в конце этого раздела.
Создание примера
Пример в этом разделе добавляется в проект, разработанный в разделе "Отмена асинхронной задачи" или "Список задач ", чтобы отменить список задач. В примере используется тот же пользовательский интерфейс, хотя кнопка "Отмена " не используется явно.
Чтобы создать пример самостоятельно, следуйте пошаговым инструкциям в разделе "Скачивание примера", но выберите CancelAListOfTasks в качестве Основного проекта. Добавьте изменения из этой темы в тот проект.
В файле MainWindow.xaml.vb проекта CancelAListOfTasks начните процесс перехода, переместив этапы обработки для каждого веб-сайта из цикла в следующий асинхронный метод.
' ***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
В этом примере используются запрос, метод AccessTheWebAsync и метод ToArray для создания и запуска массива задач. Приложение массива WhenAny возвращает одну задачу, которая, когда ожидается, оценивает первую задачу, чтобы достичь завершения в массиве задач.
Внесите следующие изменения в AccessTheWebAsync. Звездочки помечают изменения в файле кода.
Закомментируйте или удалите цикл.
Создайте запрос, который при выполнении создает коллекцию универсальных задач. Каждый вызов
ProcessURLAsyncвозвращает Task<TResult>, гдеTResultявляется целым числом.' ***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)Позвоните по
ToArray, чтобы выполнить запрос и начать задачи. ПриложениеWhenAnyметода на следующем шаге будет выполнять запрос и запускать задачи без использованияToArray, но другие методы не могут. Самая безопасная практика — принудительное выполнение запроса явным образом.' ***Use ToArray to execute the query and start the download tasks. Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()Вызов
WhenAnyколлекции задач.WhenAnyвозвращает значениеTask(Of Task(Of Integer))илиTask<Task<int>>. То есть возвращает задачу,WhenAnyкоторая оценивается как однаTask(Of Integer)илиTask<int>когда она ожидается. Эта одна задача — это первая задача в коллекции, которая будет завершена. Задача, завершиющаяся первым, назначаетсяfinishedTask. ТипfinishedTask— это Task<TResult>, гдеTResultявляется целым числом, потому что это возвращаемый типProcessURLAsync.' ***Call WhenAny and then await the result. The task that finishes ' first is assigned to finishedTask. Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)В этом примере вас интересует только задача, которая завершается первой. Поэтому используйте CancellationTokenSource.Cancel для отмены оставшихся задач.
' ***Cancel the rest of the downloads. You just want the first one. cts.Cancel()Наконец, дождитесь
finishedTask, чтобы получить длину загруженного содержимого.Dim length = Await finishedTask resultsTextBox.Text &= vbCrLf & $"Length of the downloaded website: {length}" & vbCrLf
Запустите программу несколько раз, чтобы убедиться, какая из загрузок завершается первой.
Полный пример
Следующий код представляет собой полный файл MainWindow.xaml.vb или MainWindow.xaml.cs для примера. Звездочки помечают элементы, добавленные в этот пример.
Обратите внимание, что необходимо добавить ссылку для 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 & "Download complete."
Catch ex As OperationCanceledException
resultsTextBox.Text &= vbCrLf & "Download canceled." & vbCrLf
Catch ex As Exception
resultsTextBox.Text &= vbCrLf & "Download 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()
'' Comment out or delete the loop.
''For Each url In urlList
'' ' GetAsync returns a Task(Of HttpResponseMessage).
'' ' Argument ct carries the message if the Cancel button is chosen.
'' ' Note that the Cancel button can cancel all remaining downloads.
'' Dim response As HttpResponseMessage = Await client.GetAsync(url, ct)
'' ' Retrieve the website contents from the HttpResponseMessage.
'' Dim urlContents As Byte() = Await response.Content.ReadAsByteArrayAsync()
'' resultsTextBox.Text &=
'' vbCrLf & $"Length of the downloaded string: {urlContents.Length}." & vbCrLf
''Next
' ***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 ToArray to execute the query and start the download tasks.
Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()
' ***Call WhenAny and then await the result. The task that finishes
' first is assigned to finishedTask.
Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)
' ***Cancel the rest of the downloads. You just want the first one.
cts.Cancel()
' ***Await the first completed task and display the results
' Run the program several times to demonstrate that different
' websites can finish first.
Dim length = Await finishedTask
resultsTextBox.Text &= vbCrLf & $"Length of the downloaded website: {length}" & vbCrLf
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 downloaded website: 158856
' Download complete.