2017-03-09 35 views
3

使用HttpClient将WebClient代码从.Net Framework 4.6.1转换为NetStandard 1.6,并且有一个奇怪的问题。这里是我的代码块是有问题:HttpClient奇怪的异步问题

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可能不会调用在一个没有绑定到委托的任务上,比如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); 
    } 

回答

1

TL;博士

要解决你的具体的例子,你要调用Wait()同步等待Task即可完成。 不是RunSynchronously()

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

长解释

RunSynchronously()有一个微妙的不同用法比Wait()。它运行Task同步,而Wait同步同步,但并没有规定任何应该如何运行。

RunSynchronously()它在现代TPL使用中并不是非常有用。这意味着仅在Task - 一个尚未启动。

的原因,这是不是非常有用的是,几乎所有的库方法返回一个Task将返回Task - 一个已经开始。这包括HttpClient。当你在已经启动的Task上调用它时,你会遇到你刚刚遇到的异常。

+0

好吧,我是一个白痴,或许只是有很多种语言嘎嘎! 我非常确定我已经尝试过并得到了一些异常,但我只是把'await'放在'Task'调用和volla的前面! – JW52761