gpt4 book ai didi

c# - WPF 应用程序中的调度程序实现多个异步任务

转载 作者:行者123 更新时间:2023-12-05 03:11:39 25 4
gpt4 key购买 nike

在以下 WPF 应用程序的 MSDN 示例中,它演示了多个异步 Tasksasync/await 实现, Dispatcher 对象显然未被使用/不需要,即异步执行的 Tasks 似乎可以直接访问 UI 控件(在这种情况下 resultTextBox TextBox 控件 - 查看行 resultsTextBox.Text += String.Format("\r\n下载长度:{0}", length);)。该应用已经过测试,性能符合预期。

但是,问题仍然存在如果此实现能够正确处理可能的竞争条件,例如,如果等待并完成的任务 尝试访问 TextBox 控件,而后者仍在处理来自先前完成的 Task 的更新?在实际意义上,是否仍需要 WPF Dispatcher 对象来处理 async/await 多任务实现 中的潜在并发/竞争条件问题(或者,可能是,联锁功能已经以某种方式在这种异步/等待编程构造中隐式实现)?

列表 1。 MSDN 文章“启动多个异步任务并在它们完成时处理它们”( https://msdn.microsoft.com/en-us/library/jj155756.aspx )

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

// Add a using directive and a reference for System.Net.Http.
using System.Net.Http;

// Add the following using directive.
using System.Threading;


namespace ProcessTasksAsTheyFinish
{
public partial class MainWindow : Window
{
// Declare a System.Threading.CancellationTokenSource.
CancellationTokenSource cts;

public MainWindow()
{
InitializeComponent();
}

private async void startButton_Click(object sender, RoutedEventArgs e)
{
resultsTextBox.Clear();

// Instantiate the CancellationTokenSource.
cts = new CancellationTokenSource();

try
{
await AccessTheWebAsync(cts.Token);
resultsTextBox.Text += "\r\nDownloads complete.";
}
catch (OperationCanceledException)
{
resultsTextBox.Text += "\r\nDownloads canceled.\r\n";
}
catch (Exception)
{
resultsTextBox.Text += "\r\nDownloads failed.\r\n";
}

cts = null;
}


private void cancelButton_Click(object sender, RoutedEventArgs e)
{
if (cts != null)
{
cts.Cancel();
}
}


async Task AccessTheWebAsync(CancellationToken ct)
{
HttpClient client = new HttpClient();

// Make a list of web addresses.
List<string> urlList = SetUpURLList();

// ***Create a query that, when executed, returns a collection of tasks.
IEnumerable<Task<int>> downloadTasksQuery =
from url in urlList select ProcessURL(url, client, ct);

// ***Use ToList to execute the query and start the tasks.
List<Task<int>> downloadTasks = 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.
Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks);

// ***Remove the selected task from the list so that you don't
// process it more than once.
downloadTasks.Remove(firstFinishedTask);

// Await the completed task.
int length = await firstFinishedTask;
resultsTextBox.Text += String.Format("\r\nLength of the download: {0}", length);
}
}


private List<string> SetUpURLList()
{
List<string> urls = new List<string>
{
"http://msdn.microsoft.com",
"http://msdn.microsoft.com/library/windows/apps/br211380.aspx",
"http://msdn.microsoft.com/en-us/library/hh290136.aspx",
"http://msdn.microsoft.com/en-us/library/dd470362.aspx",
"http://msdn.microsoft.com/en-us/library/aa578028.aspx",
"http://msdn.microsoft.com/en-us/library/ms404677.aspx",
"http://msdn.microsoft.com/en-us/library/ff730837.aspx"
};
return urls;
}


async Task<int> ProcessURL(string url, HttpClient client, CancellationToken ct)
{
// GetAsync returns a Task<HttpResponseMessage>.
HttpResponseMessage response = await client.GetAsync(url, ct);

// Retrieve the website contents from the HttpResponseMessage.
byte[] urlContents = await response.Content.ReadAsByteArrayAsync();

return urlContents.Length;
}
}
}

注意:我要感谢 Stephen Cleary 的出色回答和颇具洞察力的解释,同时也想强调建议的改进在他的解决方案中概述,即:使用 WhenAny 替换原始 MSDN 示例中不必要/复杂的代码块,将其替换为封装在一行代码中的相当紧凑的解决方案,即:await Task.WhenAll(downloadTasks );(顺便说一句,我在很多实用的应用程序中都使用了这个替代方案,特别是处理多股股票网络查询的在线市场数据应用程序)。非常感谢,斯蒂芬!

最佳答案

However, the question still remains if this implementation is capable of proper handling the possible race condition, for e.g., if the awaited and completed Task tries to access that TextBox control while the latter is still processing the update from previously completed Task?

没有竞争条件。 UI 线程一次只做一件事。

In practical sense, is WPF Dispatcher object still required to handle this potential concurrency/race condition issues in async/await multitasking implementation (or, may be, the interlocking functionality has been somehow implicitly implemented in such async/await programming construct)?

是的,但您不必明确使用它。正如我在 async intro 中描述的那样, await 关键字(默认情况下)将捕获当前上下文并在该上下文中继续执行 async 方法。 “上下文”是 SynchronizationContext.Current(如果当前 SyncCtx 为 null,则为 TaskScheduler.Current)。

在这种情况下,它将捕获一个 UI SynchronizationContext,它在幕后使用 WPF Dispatcher 来调度 UI 线程上的 async 方法的其余部分。

附带说明一下,我不太喜欢“Task.WhenAny 列表并在完成时从列表中删除”方法。我发现如果通过添加 DownloadAndUpdateAsync 方法进行重构,代码会更简洁:

async Task AccessTheWebAsync(CancellationToken ct)
{
HttpClient client = new HttpClient();

// Make a list of web addresses.
List<string> urlList = SetUpURLList();

// ***Create a query that, when executed, returns a collection of tasks.
IEnumerable<Task> downloadTasksQuery =
from url in urlList select DownloadAndUpdateAsync(url, client, ct);

// ***Use ToList to execute the query and start the tasks.
List<Task> downloadTasks = downloadTasksQuery.ToList();

await Task.WhenAll(downloadTasks);
}

async Task DownloadAndUpdateAsync(string url, HttpClient client, CancellationToken ct)
{
var length = await ProcessURLAsync(url, client, ct);
resultsTextBox.Text += String.Format("\r\nLength of the download: {0}", length);
}

async Task<int> ProcessURLAsync(string url, HttpClient client, CancellationToken ct)
{
// GetAsync returns a Task<HttpResponseMessage>.
HttpResponseMessage response = await client.GetAsync(url, ct);

// Retrieve the website contents from the HttpResponseMessage.
byte[] urlContents = await response.Content.ReadAsByteArrayAsync();

return urlContents.Length;
}

关于c# - WPF 应用程序中的调度程序实现多个异步任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36481643/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com