在执行get方法的异步调用时在主代码中等待
本文关键字:代码 等待 异步 执行 get 方法 调用 | 更新日期: 2023-09-27 17:50:31
void main() {
OpenWeatherApiClient.getCurrentLocationWeatherAsync(55.513434, -37.53434, (x) => {
Console.WriteLine(x.coord.lat);
Console.ReadLine();
});
}
Console.WriteLine("this should happen before");
/// I want to hold the the function here till the call back returns and executes the above logic
/// the asynchronous function
public static void getCurrentLocationWeatherAsync(double latitude, double longitude, Action<WeatherData> callback) {
//weather from one station
string weatherSearch = "weather?lat={0}&lon={1}";
var url = string.Concat(baseUrl, weatherSearch);
//Customize the URL according to the geo location
url = string.Format(url, latitude, longitude);
//Syncronous consumption
var asynClient = new WebClient();
//add Appid for verification
asynClient.Headers.Add(APPIDName, APPID);
asynClient.OpenReadCompleted += (o, a) => {
if (callback != null) {
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(WeatherData));
callback(ser.ReadObject(a.Result) as WeatherData);
}
};
asynClient.OpenReadAsync(new Uri(url));
}
我有女仆这个异步get方法,解析成数据合同后的请求。虽然我想保持主方法,直到getcall和关联代码在委托完全执行。在未来,我想要的是并发调用多于get方法,并保持它们,直到它们全部执行。之后,我将在主程序中继续,因为每个get调用的数据都是依赖的
如果我没理解错的话:
private static readonly List<Task> weatherTasks = new List<Task>();
public static void GetCurrentLocationWeatherAsync(double latitude, double longitude, Action<WeatherData> callback)
{
// ...
weatherTasks.Add(asynClient.OpenReadTaskAsync(new Uri(url)));
}
public static void WaitForAllWeatherCalls()
{
Task.WaitAll(weatherTasks.ToArray());
weatherTasks.Clear();
}
创建任务列表,然后将OpenReadAsync
更改为OpenReadTaskAsync
,并将任务放入列表中。方法WaitForAllWeatherCalls
然后只是等待所有当前运行的任务,然后清除任务(请注意,代码不是线程安全的)。
为什么这个代码不是线程安全的:假设我们有一个线程a和一个线程b。a多次调用GetCurrentLocationWeatherAsync
,然后想要等待这些调用。所以线程A调用WaitForAllWeatherCalls
,现在正在等待。当线程A在等待时,线程B也想获得一些天气数据。线程B多次调用GetCurrentLocationWeatherAsync
。任务列表中现在包含了一些线程A的任务和一些线程b的任务。当线程A的等待结束后,问题出现了,因为任务列表将被清除。当线程B想要等待他所有的数据时,列表中不会有任何任务,线程B甚至不会暂停一次。
更好的版本:
class WeatherGatherer
{
private readonly List<Task> weatherTasks = new List<Task>();
public void GetCurrentLocationWeatherAsync(double latitude, double longitude, Action<WeatherData> callback)
{
// ...
weatherTasks.Add(asynClient.OpenReadTaskAsync(new Uri(url)));
}
public void WaitForAllWeatherCalls()
{
Task.WaitAll(weatherTasks.ToArray());
weatherTasks.Clear();
}
}
洞的东西现在是一个类,而不是静态的。类本身仍然不是线程安全的,但如果你总是为一组'weather-data gathering'创建一个实例,你就不会有问题。
请记住,只有当你有多个线程时,线程安全才是一个问题。
任何替代上述逻辑的方法也会非常好
我之前是这样做的,但不能继续,因为事件不会返回反序列化的对象
//public static async Task<WeatherData> getCurrentLocationWeatherAsync(double latitude, double longitude)
//{
// //weather from one station
// string weatherSearch = "weather?lat={0}&lon={1}";
// var url = string.Concat(baseUrl, weatherSearch);
// //Customize the URL according to the geo location
// url = string.Format(url,latitude, longitude);
// //Syncronous consumption
// var asynClient = new WebClient();
// //add Appid for verification
// asynClient.Headers.Add(APPIDName,APPID);
// asynClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(asyncClient_DownloadStringCompleted);
// // API call
// var response = await asynClient.DownloadStringTaskAsync(url);
// //content=content.Replace("3h", "precipitation__3h");
// //create Json Serializer and parse the response
//}
//static void asyncClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
//{
// // Create the Json serializer and parse the response
// DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(WeatherData));
// using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(e.Result)))
// {
// // deserialize the JSON object using the WeatherData type.
// var weatherData = (WeatherData)serializer.ReadObject(ms);
// // return weatherData;
// }
//}