[英]Using Multithreading with Async-await C#
I wrote an async function for calling data from Facebook, it works, but the problem is I dun suppose it works. 我写了一个异步函数来从Facebook调用数据,它可以工作,但是问题是我认为它可以工作。 Can someone explain to me?
有人可以向我解释吗?
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);
}
}
The calling class is typical, I make it await for the response. 调用类是典型的,我让它等待响应。
But the problem is where I call it. 但是问题出在哪里。
In main 在主要
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
}
}
In facebookRequestCmd 在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
}
}
In my understanding, each time I call getData, it already come back to main thread, as it is awaiting the data. 据我了解,每次调用getData时,它都在等待数据时已经返回主线程。 So the Task doesn't really start a new thread.
因此,该Task并未真正启动新线程。
Thus, async await works for waiting the http request, but the Threading should not work. 因此,async await用于等待http请求,但是Threading不起作用。
However, 然而,
Console.WriteLine("Running Thread " + (i+1).ToString());
jumps out simultaneously like I really make the Thread in the for loop in main function. 就像我真的在main函数的for循环中创建Thread一样同时跳出。
Why? 为什么? And is that the way to use Multithreading with Async-await.
这就是在异步等待中使用多线程的方式。 As I want to make multiple calls at the same time.
由于我想同时拨打多个电话。
Originally I use Parallel.ForEach to kick starting the calling, however, thats not asynchronous and will block the thread. 最初,我使用Parallel.ForEach来启动调用,但是那不是异步的,并且会阻塞线程。
Ok, feel free to ignore all the changes I've made but I couldn't help but modify the way some of the variables read and the code looked. 好的,可以随意忽略我所做的所有更改,但是我不得不修改某些变量的读取方式和代码的外观。 This is not a working application and I have obviously not tested it.
这不是一个有效的应用程序,我显然没有对其进行测试。 This is just a cleaned up version of what you have with a suggested way of using
Task
. 这只是使用
Task
的建议方式清除的内容。 It's also mocked using just the code you've provided so it is what it is. 它也仅使用您提供的代码进行了模拟,因此就是它的样子。 #2 is, what I believe, the answer you needed.
#2是我所相信的,您需要的答案。
Main
I removed the words 'thread' since that's not actually what's happening. Main
我删除了“线程”一词,因为这实际上并没有发生。 It may be, but we don't know if the HttpClient is indeed starting a new thread or just holding / returning from the rest call. async
/ await
does not always mean a Thread
was started (although it's common to think of it that way). async
/ await
并不总是意味着启动了一个Thread
(尽管通常以这种方式来考虑)。 .Result
(not Wait()
as I suggested in comments) to get the result of the task. .Result
(不是我在注释中建议的Wait()
)来获取任务的结果。 This is ok since it's a console app but not ideal for a real world app that needs to operate without blocking. Task.WaitAll
with this change. Task.WaitAll
。 Type
that makes sense. Type
。 Task
. Task
函数名称后附加了“异步”。 FacebookClient
to be singleton and allowing only one HttpClient
to be used instead of many and allowing it to be disposed; FacebookClient
更改为单例,只允许使用一个HttpClient
而不是多个HttpClient
并允许将其处置; plus more. GetFacebookData
function that calls the tasks and awaits them all simultaneously. 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();
}
Here's a version that's starting all the tasks and then awaiting them all at the same time. 这是一个开始所有任务然后同时等待所有任务的版本。 I believe this might give you some issues on the
HttpClient
but we'll see. 我相信这可能会给您
HttpClient
带来一些问题,但是我们会看到的。
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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.