gpt4 book ai didi

c# - HttpClient 的奇怪异步问题

转载 作者:行者123 更新时间:2023-11-30 17:34:21 25 4
gpt4 key购买 nike

致力于使用 HttpClient 将 WebClient 代码从 .Net Framework 4.6.1 转换为 NetStandard 1.6,但遇到了一个奇怪的问题。这是我有问题的代码块:

public double TestDownloadSpeed(Server server, int simultaniousDownloads = 2, int retryCount = 2)
{
var testData = GenerateDownloadUrls(server, retryCount);

return TestSpeed(testData, async (client, url) =>
{
var data = await client.GetByteArrayAsync(url);

return data.Length;
}, simultaniousDownloads);
}

public double TestUploadSpeed(Server server, int simultaniousUploads = 2, int retryCount = 2)
{
var testData = GenerateUploadData(retryCount);

return TestSpeed(testData, async (client, uploadData) =>
{
client.PostAsync(server.Url, new StringContent(uploadData.ToString())).RunSynchronously();

return uploadData[0].Length;
}, simultaniousUploads);
}

private static double TestSpeed<T>(IEnumerable<T> testData, Func<HttpClient, T, Task<int>> doWork, int concurencyCount = 2)
{
var timer = new Stopwatch();
var throttler = new SemaphoreSlim(concurencyCount);

timer.Start();

var downloadTasks = testData.Select(async data =>
{
await throttler.WaitAsync().ConfigureAwait(true);
var client = new CoreSpeedWebClient();
try
{
var size = await doWork(client, data).ConfigureAwait(true);
return size;
}
finally
{
client.Dispose();
throttler.Release();
}
}).ToArray();

Task.Run(() => downloadTasks);

timer.Stop();

double totalSize = downloadTasks.Sum(task => task.Result);

return (totalSize * 8 / 1024) / ((double)timer.ElapsedMilliseconds / 1000);
}

所以,当调用 TestDownloadSpeed 函数时,一切都按预期工作,但是当我调用 TestUploadSpeed 方法时,我收到错误 InvalidOperationException: RunSynchronously may not be called on a task未绑定(bind)到委托(delegate),例如从异步方法返回的任务。* 在 TestSpeed 的这一部分。

double totalSize = downloadTasks.Sum(task => task.Result);

我真的绞尽脑汁想弄清楚 TestUploadSpeed 中的什么东西导致了问题。任何人有任何提示指向正确的方向吗?

如果有帮助,这里是 .Net 4.6.1 代码,可以正常工作,所以也许我的翻译有问题?再加上原始代码的运行速度大约快 5 倍,所以不确定那是什么......

    public double TestDownloadSpeed(Server server, int simultaniousDownloads = 2, int retryCount = 2)
{
var testData = GenerateDownloadUrls(server, retryCount);

return TestSpeed(testData, async (client, url) =>
{
var data = await client.DownloadDataTaskAsync(url).ConfigureAwait(false);
return data.Length;
}, simultaniousDownloads);
}

public double TestUploadSpeed(Server server, int simultaniousUploads = 2, int retryCount = 2)
{
var testData = GenerateUploadData(retryCount);
return TestSpeed(testData, async (client, uploadData) =>
{
await client.UploadValuesTaskAsync(server.Url, uploadData).ConfigureAwait(false);
return uploadData[0].Length;
}, simultaniousUploads);
}

private static double TestSpeed<T>(IEnumerable<T> testData, Func<WebClient, T, Task<int>> doWork, int concurencyCount = 2)
{
var timer = new Stopwatch();
var throttler = new SemaphoreSlim(concurencyCount);

timer.Start();
var downloadTasks = testData.Select(async data =>
{
await throttler.WaitAsync().ConfigureAwait(false);
var client = new SpeedTestWebClient();
try
{
var size = await doWork(client, data).ConfigureAwait(false);
return size;
}
finally
{
client.Dispose();
throttler.Release();
}
}).ToArray();

Task.WaitAll(downloadTasks);
timer.Stop();

double totalSize = downloadTasks.Sum(task => task.Result);
return (totalSize * 8 / 1024) / ((double)timer.ElapsedMilliseconds / 1000);
}

最佳答案

tl;dr

要修复您的具体示例,您需要调用 Wait() 以同步等待 Task 完成。 不是 RunSynchronously()

但您可能实际上想要await Task 以允许异步完成。 Wait() 在大多数情况下对性能来说不是很好,并且具有一些如果使用不当可能导致死锁的特征。

详细解释

RunSynchronously()Wait() 的用法略有不同。它同步运行 Task,而Wait 将同步等待,但不规定任何关于它应该如何运行的内容.

RunSynchronously() 它在现代 TPL 使用中不是很有用。它只能在 Task -- 尚未启动的情况下调用。

这不是很有用的原因是几乎每个返回 Task 的库方法都会返回一个 hot Task --一个已经开始的。这包括来自 HttpClient 的那些。当您在已经启动的 Task 上调用它时,您会得到刚刚遇到的异常。

关于c# - HttpClient 的奇怪异步问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42686079/

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