【发布时间】:2019-11-14 23:25:34
【问题描述】:
我继承了一些代码,该模式(简化)被用于每秒轮询设备并通过它的 REST api 检查它是否有新数据:
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.Net.Http;
public class Class
{
private readonly string _iotIPaddress = "123.456.789.0";
private System.Timers.Timer _timer = null;
private readonly HttpClient _client = new HttpClient();
public Constructor()
{
_client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(--secrets--);
_client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
_timer = new System.Timers.Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
_timer.Elapsed += OnTimer;
}
private async void OnTimer(object sender, EventArgs e)
{
try
{
_timer.Stop();
var success = await ProcessUpdates();
// Some stuff depending on whether ProcessUpdates succeeded
}
catch (Exception ex)
{
// Log the exception
}
finally
{
_timer.Start();
}
}
private async Task<SomeSettingsStruct> ProcessUpdates()
{
try
{
string json = await _client.GetStringAsync($"http://{_iotIPaddress}/di_value/slot_0"); //Exception is thrown on this line
var resultdata = JsonConvert.DeserializeObject<SomeSettingsStruct>(json);
return resultdata;
}
catch (Exception e)
{
//Log the exception
return null;
}
}
}
而且大多数时候这都很好。但是偶尔连接会滞后(设备通过 wifi 连接)并且 GetStringAsync 会抛出一些预期的异常(呵呵),但有时这似乎会导致代码长时间阻塞。这可能表明网络问题持续时间超过几分钟,但现场人员不认为是这种情况。因此问题一定出在代码的某个地方。
尤其是这个异步回调方法不适合我,计时器无论如何都会在不同的线程上调用它的回调,那么回调中的异步/等待内容会发生什么?那些是在计时器线程上调用的还是他们自己的任务? 这会导致竞争条件,用 HttpClient 做奇怪的事情吗?
这是我在日志中得到的异常:
在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 在 Example.Namespace.Class.d__13.MoveNext() 在 C: \dev\Project\Example\Namespace\Class.cs:103 行
而且由于我们还记录了 FirstChanceExceptions,所以我经常看到这种情况发生之前:
发生异常:由于线程退出或应用程序请求 123.456.789.0:80,I/O 操作已中止
【问题讨论】:
-
为什么
private async SomeSettingsStruct ProcessUpdates()不像private async Task<SomeSettingsStruct> ProcessUpdates()?您的“结构”中有自定义等待者吗? -
@JoePhillips
OnTimer是一个事件处理程序,所以async void很好,在这里。 -
@Fildor 不是
async void,而是async Something。这是无效的语法。 -
事件处理程序仍然是
async void,这意味着没有任何事情等待它完成。如果应用程序终止,它仍将运行,其线程将被中止。 -
@Fildor 哎呀,把 cmets 搞混了。 ` async SomeSettingsStruct ProcessUpdates` 是无效的语法,但我认为这是一个错字,确实是
async Task<SomeSettingsStruct> ProcessUpdates
标签: c# .net multithreading http async-await