代码之家  ›  专栏  ›  技术社区  ›  MT-FreeHK

使用异步等待C的多线程#

  •  0
  • MT-FreeHK  · 技术社区  · 7 年前

    我写了一个异步函数来从Facebook调用数据,它可以工作,但问题是我不认为它可以工作。有人能给我解释一下吗?

    public class FacebookData
        {
            static string fb_api_version = ConfigurationManager.AppSettings["fb_ver"];
            static string accessToken = ConfigurationManager.AppSettings["accessToken"];
            static string fb_id = "";
            private HttpClient _httpClient;
            public FacebookData(string input_id)
            {
                fb_id = input_id;
                _httpClient = new HttpClient
                {
                    BaseAddress = new Uri("https://graph.facebook.com/" + fb_api_version + "/"),
                    Timeout = TimeSpan.FromSeconds(15)
                };
                _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            }
    
            public async Task<T> getData<T>()
            {
                var response = await _httpClient.GetAsync($"{fb_id}?access_token={accessToken}");
                if (!response.IsSuccessStatusCode)
                    return default(T);
    
                var result = await response.Content.ReadAsStringAsync();
                return JsonConvert.DeserializeObject<T>(result);
            }
        }
    

    调用类是典型的,我让它等待响应。

    但问题是我怎么称呼它。

    主要

    static void Main(string[] args)
    {
       string[] data_Set = [//ids_group]
    
       for (int i = 0; i < data_Set.length; ++i){
           Console.WriteLine("Running Thread " + (i+1).ToString());
           var dataSet = facebookRequestCmd(data_Set[i]);
           writeToTXT(dataSet);
           Console.WriteLine("Finished Thread " + (i + 1).ToString());
           //do sth
       }
    }
    

    在facebookrequestCmd中

    static Dictionary<string, string[]> facebookRequestCmd(string ids){
       Dictionary<string, string[]> allData = new Dictionary<string, string[]>();
       string[] ids_arr = ids.split(",")
       for (var i = 0; i < ids.length; i++){
          var facebook_client = new FacebookData(sqlData);
          var response = facebook_client.getData<dynamic>();
          Task.WaitAll(response);
    
          //then use the result to do sth
       }
    }
    

    据我所知,每次调用getdata时,它都会返回到主线程,因为它正在等待数据。所以任务并不能真正启动一个新的线程。

    因此,AsyncWait在等待HTTP请求时工作,但线程不应该工作。

    然而,

    Console.WriteLine("Running Thread " + (i+1).ToString());
    

    同时跳出,就像我真的在主函数的for循环中创建线程一样。

    为什么?这就是使用异步等待多线程的方法。因为我想同时打多个电话。

    最初我使用parallel.foreach启动调用,但是这不是异步的,并且会阻塞线程。

    1 回复  |  直到 7 年前
        1
  •  2
  •   Michael Puckett II    7 年前

    好吧,可以忽略我所做的所有更改,但是我不得不修改一些变量的读取方式和代码的外观。这不是一个有效的应用程序,我显然没有测试过它。这只是一个清理过的版本,有一个建议的使用方法 Task .它也被嘲笑使用的只是你提供的代码,所以它是什么。#2是,我相信,你需要的答案。

    1. Main 我去掉了“线程”这个词,因为事实上这不是发生的事情。可能是这样,但是我们不知道httpclient是否真的正在启动一个新线程,或者只是保持/返回剩余的调用。使用 async / await 并不总是意味着 Thread 开始了(尽管这样想很常见)。
    2. 我用过 .Result (不是 Wait() 正如我在评论中建议的那样)获得任务的结果。这是可以的,因为它是一个控制台应用程序,但不理想的现实世界的应用程序,需要运行而不阻塞。我也移除了 Task.WaitAll 有了这个变化。
    3. 我将函数重命名为具有措辞,因为在IMO中,函数应该执行工作,命名应该描述正在执行的工作。
    4. 我重命名了一些变量,因为在imo中,当变量的作用域不在方法中时,变量应该是pascalcase;当变量在方法中时,应该是private和camelcase。在我看来,名字后面应该是 Type 这是有道理的。
    5. 我在返回的函数名后面附加了“async” 任务 .
    6. 改变 FacebookClient 单身,只允许一个 HttpClient 用以代替许多,并允许它被处理;加上更多。
    7. 添加了 GetFacebookData 调用任务并同时等待它们的函数。

    static void Main(string[] args)
    {
        string[] dataSet = new string[] { /* mocked */ };  // [ids_group]; <- no idea what this is so I mocked it.
    
        for (int i = 0; i < dataSet.Length; i++)
        {
            Console.WriteLine("Main... " + (i + 1).ToString());
            var result = GetFacebookData(dataSet[i]);
            WriteToTxt(result);
            Console.WriteLine("Complete... " + (i + 1).ToString());
            //do sth
        }
    
        Console.Read();
    }
    
    private static Dictionary<string, string[]> GetFacebookData(string idsString)
    {
        var allDataDictionary = new Dictionary<string, string[]>();
        var idsArray = idsString.Split(',');
    
        foreach (var id in idsArray)
        {
            var response = FacebookClient.Instance.GetDataAsync<string[]>(id).Result;
            allDataDictionary.Add(id, response);
        }
    
        return allDataDictionary;
    }
    

    public class FacebookClient
    {
        private readonly HttpClient httpClient;
        private readonly string facebookApiVersion;
        private readonly string accessToken;
    
        public static FacebookClient Instance { get; } = new FacebookClient();
    
        FacebookClient()
        {
            facebookApiVersion = ConfigurationManager.AppSettings["fb_ver"];
            accessToken = ConfigurationManager.AppSettings["accessToken"];
    
            httpClient = new HttpClient
            {
                BaseAddress = new Uri("https://graph.facebook.com/" + facebookApiVersion + "/"),
                Timeout = TimeSpan.FromSeconds(15)
            };
    
            httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        }
    
        public async Task<T> GetDataAsync<T>(string facebookId)
        {
            var response = await httpClient.GetAsync($"{facebookId}?access_token={accessToken}");
            if (!response.IsSuccessStatusCode) return default;
            var result = await response.Content.ReadAsStringAsync();
            return JsonConvert.DeserializeObject<T>(result);
        }
    
        ~FacebookClient() => httpClient.Dispose();
    }
    

    这是一个启动所有任务然后同时等待所有任务的版本。我相信这可能会给你一些关于 http客户端 但我们会看到的。


    private static Dictionary<string, string[]> GetFacebookData(string idsString)
    {
        var allDataDictionary = new Dictionary<string, string[]>();
        var idsArray = idsString.Split(',');
        var getDataTasks = new List<Task<string[]>>();
    
        foreach (var id in idsArray)
        {
            getDataTasks.Add(FacebookClient.Instance.GetDataAsync<string[]>(id));         
        }
    
        var tasksArray = getDataTasks.ToArray();
        Task.WaitAll(tasksArray);
        var resultsArray = tasksArray.Select(task => task.Result).ToArray();
    
        for (var i = 0; i < idsArray.Length; i++)
        {
            allDataDictionary.Add(idsArray[i], resultsArray[i]);
        }
    
        return allDataDictionary;
    }
    
    推荐文章