gpt4 book ai didi

c# - 无法调试使用并发异步/等待的程序

转载 作者:太空宇宙 更新时间:2023-11-03 20:21:42 26 4
gpt4 key购买 nike

观察 on this program :

  • 在此程序中缓慢按 F11 不会显示 ProcessURL()

  • 的每次执行
  • 在这个程序中快速按 F11 会显示更多的 ProcessURL()

  • 执行
  • 在 ProcessURL 中使用 Thread.Sleep(3000); 会导致 MainUI 线程挂起大约 30 秒。没有 UI 重绘,并且取消按钮不可用。

需要:

  • 我想逐步完成 ProcessURL 的每次执行,或者可能使用 native Visual Studio 工具或开源插件将其可视化

enter image description here

代码

Download available here

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;
}
}
}

最佳答案

假设您在 await 调用之前调用了 Thread.Sleep ,那么 UI 线程锁定是完全合理的:您正在阻止它。您的 ProcessURL 方法将同步执行,直到您为尚未完成的事情命中第一个 await 表达式。当它到达那里时,它将附加一个延续然后返回。

因此,如果您在等待之前调用了 Thread.Sleep,当执行 LINQ 查询时(当您调用 ToList 时,您将调用该方法 7 次连续,每次在 UI 线程中休眠 3 秒。当发生这种情况时,UI 将被锁定。如果你将 Thread.Sleep 放在 之后 await,那么 UI 仍将被锁定相同的时间,但会以较小的时间间隔锁定。

Thread.Sleep 的异步等价物是使用 Task.Delay :

await Task.Delay(3000);

这基本上会立即返回,附加一个将在 3 秒内触发的延续。

(我不知道调试问题 - 我不会尝试调试 大多数这些语句......我不清楚你到底想达到什么目的或为什么。ProcessURL 中的断点应该为每个 URL 命中。)

关于c# - 无法调试使用并发异步/等待的程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13087188/

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