C# 您是否需要后台工作线程或多个线程来触发多个异步HttpWebRequests? 总体目标
我试图通过从C# 您是否需要后台工作线程或多个线程来触发多个异步HttpWebRequests? 总体目标,c#,multithreading,asynchronous,httpwebrequest,backgroundworker,C#,Multithreading,Asynchronous,Httpwebrequest,Backgroundworker,我试图通过从.txt文件读取的多输入URL调用,并将结果输出到.csv 我试过的 我编写了一个控制台应用程序来尝试触发这些请求,然后当它们返回并添加到列表中时,当它们全部完成时,将列表写入.csv文件(async在尝试立即将响应写入.csv时有点疯狂) 我的代码如下所示,远未优化。我来自JavaScript背景,通常不使用web workers或任何其他托管新线程,因此我尝试在C#中使用同样的方法 我可以运行多个WebRequests并将它们写入一个集合(或输出文件),而不使用多个线程,并让它们
.txt
文件读取的多输入URL调用,并将结果输出到.csv
我试过的
我编写了一个控制台应用程序来尝试触发这些请求,然后当它们返回并添加到列表中时,当它们全部完成时,将列表
写入.csv
文件(async在尝试立即将响应写入.csv
时有点疯狂)
我的代码如下所示,远未优化。我来自JavaScript背景,通常不使用web workers或任何其他托管新线程,因此我尝试在C#中使用同样的方法
WebRequest
s并将它们写入一个集合(或输出文件),而不使用多个线程,并让它们并行运行,而不必等待每个请求返回,然后再处理下一个请求吗BackgroundWorker
s,有什么办法static void Main(字符串[]args)
{
WriteLine(“开始谷歌PageSpeed洞察!”);
appMode=ConfigurationManager.AppSettings[“ApplicationMode”];
var inputFilePath=READ_WRITE_PATH+ConfigurationManager.AppSettings[“InputFile”];
var outputFilePath=READ_WRITE_PATH+ConfigurationManager.AppSettings[“OutputFile”];
var inputLines=File.ReadAllLines(inputFilePath.ToList();
if(File.Exists(outputFilePath))
{
File.Delete(outputFilePath);
}
List outputCache=新列表();
foreach(输入行中的var行)
{
var requestDataFromPsi=CallPsiForPrimaryStats(行);
WriteLine($“获取了{requestDataFromPsi.Result}的响应”);
Add(requestDataFromPsi.Result);
}
var writeTask=WriteCharacters(outputCache,outputFilePath);
writeTask.Wait();
Console.WriteLine(“结束Google PageSpeed Insights”);
}
私有静态异步任务CallPsiForPrimaryStats(字符串url)
{
HttpWebRequest myReq=(HttpWebRequest)WebRequest.Create($)https://www.googleapis.com/pagespeedonline/v2/runPagespeed?url={url}&strategy=mobile&key={API_key}”);
myReq.Method=WebRequestMethods.Http.Get;
myReq.Timeout=60000;
myReq.Proxy=null;
myReq.ContentType=“应用程序/json”;
Task Task=Task.Factory.fromsync(
myReq.BeginGetResponse,
asyncResult=>myReq.EndGetResponse(asyncResult),
(对象为空);
返回等待任务。继续(t=>ReadStreamFromResponse(t.Result));
}
私有静态字符串ReadStreamFromResponse(WebResponse响应)
{
使用(Stream responseStream=response.GetResponseStream())
使用(StreamReader sr=新StreamReader(responseStream))
{
字符串jsonResponse=sr.ReadToEnd();
动态jsonObj=Newtonsoft.Json.JsonConvert.DeserializeObject(jsonResponse);
var psiResp=新的PsiResponse()
{
Url=jsonObj.id,
SpeedScore=jsonObj.ruleGroups.SPEED.score,
UsabilityScore=jsonObj.ruleGroups.USABILITY.score,
NumberResources=jsonObj.pageStats.NumberResources,
NumberHosts=jsonObj.pageStats.NumberHosts,
TotalRequestBytes=jsonObj.pageStats.TotalRequestBytes,
NumberStaticResources=jsonObj.pageStats.NumberStaticResources,
HtmlResponseBytes=jsonObj.pageStats.HtmlResponseBytes,
CssResponseBytes=jsonObj.pageStats.CssResponseBytes,
ImageResponseBytes=jsonObj.pageStats.ImageResponseBytes,
JavascriptResponseBytes=jsonObj.pageStats.JavascriptResponseBytes,
OtherResponseBytes=jsonObj.pageStats.OtherResponseBytes,
NumberJsResources=jsonObj.pageStats.NumberJsResources,
numbercsresources=jsonObj.pageStats.numbercsresources,
};
返回CreateOutputString(PSIREP);
}
}
静态异步任务WriteCharacters(列表输入、字符串输出文件路径)
{
使用(StreamWriter fileWriter=newstreamwriter(outputFilePath))
{
等待fileWriter.WriteLineAsync(表头);
foreach(输入中的var输入)
{
等待fileWriter.WriteLineAsync(输入);
}
}
}
专用静态字符串CreateOutputString(PsiResponse PsiResponse)
{
var stringToWrite=“”;
foreach(psiResponse.GetType().GetProperties()中的var prop)
{
stringToWrite+=$“{prop.GetValue(psiResponse,null)},”;
}
控制台写入线(stringToWrite);
返回stringToWrite;
}
更新:Stephen Cleary Tips重构后
问题是这仍然运行缓慢。最初的需要20分钟,重构后仍然需要20分钟。它似乎在某个地方被限制了,可能是谷歌在PageSpeed API上限制的。我对它进行了测试、呼叫和其他18次测试,它运行速度也很慢,一次只能处理大约5个请求。我尝试重构运行5个测试URL,然后写入文件并重复,但这只是略微加快了过程
static void Main(string[] args) { MainAsync(args).Wait(); }
static async Task MainAsync(string[] args)
{
Console.WriteLine("Begin Google PageSpeed Insights!");
appMode = ConfigurationManager.AppSettings["ApplicationMode"];
var inputFilePath = READ_WRITE_PATH + ConfigurationManager.AppSettings["InputFile"];
var outputFilePath = READ_WRITE_PATH + ConfigurationManager.AppSettings["OutputFile"];
var inputLines = File.ReadAllLines(inputFilePath).ToList();
if (File.Exists(outputFilePath))
{
File.Delete(outputFilePath);
}
var tasks = inputLines.Select(line => CallPsiForPrimaryStats(line));
var outputCache = await Task.WhenAll(tasks);
await WriteCharacters(outputCache, outputFilePath);
Console.WriteLine("End Google PageSpeed Insights");
}
private static async Task<string> CallPsiForPrimaryStats(string url)
{
HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create($"https://www.googleapis.com/pagespeedonline/v2/runPagespeed?url={url}&strategy=mobile&key={API_KEY}");
myReq.Method = WebRequestMethods.Http.Get;
myReq.Timeout = 60000;
myReq.Proxy = null;
myReq.ContentType = "application/json";
Console.WriteLine($"Start call: {url}");
// Try using `HttpClient()` later
//var myReq2 = new HttpClient();
//await myReq2.GetAsync($"https://www.googleapis.com/pagespeedonline/v2/runPagespeed?url={url}&strategy=mobile&key={API_KEY}");
Task<WebResponse> task = Task.Factory.FromAsync(
myReq.BeginGetResponse,
myReq.EndGetResponse,
(object)null);
var result = await task;
return ReadStreamFromResponse(result);
}
private static string ReadStreamFromResponse(WebResponse response)
{
using (Stream responseStream = response.GetResponseStream())
using (StreamReader sr = new StreamReader(responseStream))
{
string jsonResponse = sr.ReadToEnd();
dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonResponse);
var psiResp = new PsiResponse()
{
Url = jsonObj.id,
SpeedScore = jsonObj.ruleGroups.SPEED.score,
UsabilityScore = jsonObj.ruleGroups.USABILITY.score,
NumberResources = jsonObj.pageStats.numberResources,
NumberHosts = jsonObj.pageStats.numberHosts,
TotalRequestBytes = jsonObj.pageStats.totalRequestBytes,
NumberStaticResources = jsonObj.pageStats.numberStaticResources,
HtmlResponseBytes = jsonObj.pageStats.htmlResponseBytes,
CssResponseBytes = jsonObj.pageStats.cssResponseBytes,
ImageResponseBytes = jsonObj.pageStats.imageResponseBytes,
JavascriptResponseBytes = jsonObj.pageStats.javascriptResponseBytes,
OtherResponseBytes = jsonObj.pageStats.otherResponseBytes,
NumberJsResources = jsonObj.pageStats.numberJsResources,
NumberCssResources = jsonObj.pageStats.numberCssResources,
};
return CreateOutputString(psiResp);
}
}
static async Task WriteCharacters(IEnumerable<string> inputs, string outputFilePath)
{
using (StreamWriter fileWriter = new StreamWriter(outputFilePath))
{
await fileWriter.WriteLineAsync(TABLE_HEADER);
foreach (var input in inputs)
{
await fileWriter.WriteLineAsync(input);
}
}
}
private static string CreateOutputString(PsiResponse psiResponse)
{
var stringToWrite = "";
foreach (var prop in psiResponse.GetType().GetProperties())
{
stringToWrite += $"{prop.GetValue(psiResponse, null)},";
}
Console.WriteLine(stringToWrite);
return stringToWrite;
}
static void Main(字符串[]args){mainsync(args.Wait();}
静态异步任务mainsync(字符串[]args)
{
WriteLine(“开始谷歌PageSpeed洞察!”);
appMode=ConfigurationManager.AppSettings[“ApplicationMode”];
var inputFilePath=READ_WRITE_PATH+ConfigurationManager.AppSettings[“InputFile”];
var outputFilePath=READ_WRITE_PATH+ConfigurationManager.AppSettings[“OutputFile”];
var inputLines=File.ReadAllLines(inputFilePath.ToList();
if(File.Exists(outputFilePath))
{
File.Delete(outputFilePath);
}
var tasks=inputLines.Select(line=>CallPsiForPrimaryStats(line));
var outputCache=wait Task.WhenAll(任务);
等待写入字符(outputCache、outputFilePath);
Console.WriteLine(“结束Google PageSpeed Insights”);
static void Main(string[] args) { MainAsync(args).Wait(); }
static async Task MainAsync(string[] args)
{
Console.WriteLine("Begin Google PageSpeed Insights!");
appMode = ConfigurationManager.AppSettings["ApplicationMode"];
var inputFilePath = READ_WRITE_PATH + ConfigurationManager.AppSettings["InputFile"];
var outputFilePath = READ_WRITE_PATH + ConfigurationManager.AppSettings["OutputFile"];
var inputLines = File.ReadAllLines(inputFilePath).ToList();
if (File.Exists(outputFilePath))
{
File.Delete(outputFilePath);
}
var tasks = inputLines.Select(line => CallPsiForPrimaryStats(line));
var outputCache = await Task.WhenAll(tasks);
await WriteCharacters(outputCache, outputFilePath);
Console.WriteLine("End Google PageSpeed Insights");
}
private static async Task<string> CallPsiForPrimaryStats(string url)
{
HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create($"https://www.googleapis.com/pagespeedonline/v2/runPagespeed?url={url}&strategy=mobile&key={API_KEY}");
myReq.Method = WebRequestMethods.Http.Get;
myReq.Timeout = 60000;
myReq.Proxy = null;
myReq.ContentType = "application/json";
Console.WriteLine($"Start call: {url}");
// Try using `HttpClient()` later
//var myReq2 = new HttpClient();
//await myReq2.GetAsync($"https://www.googleapis.com/pagespeedonline/v2/runPagespeed?url={url}&strategy=mobile&key={API_KEY}");
Task<WebResponse> task = Task.Factory.FromAsync(
myReq.BeginGetResponse,
myReq.EndGetResponse,
(object)null);
var result = await task;
return ReadStreamFromResponse(result);
}
private static string ReadStreamFromResponse(WebResponse response)
{
using (Stream responseStream = response.GetResponseStream())
using (StreamReader sr = new StreamReader(responseStream))
{
string jsonResponse = sr.ReadToEnd();
dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonResponse);
var psiResp = new PsiResponse()
{
Url = jsonObj.id,
SpeedScore = jsonObj.ruleGroups.SPEED.score,
UsabilityScore = jsonObj.ruleGroups.USABILITY.score,
NumberResources = jsonObj.pageStats.numberResources,
NumberHosts = jsonObj.pageStats.numberHosts,
TotalRequestBytes = jsonObj.pageStats.totalRequestBytes,
NumberStaticResources = jsonObj.pageStats.numberStaticResources,
HtmlResponseBytes = jsonObj.pageStats.htmlResponseBytes,
CssResponseBytes = jsonObj.pageStats.cssResponseBytes,
ImageResponseBytes = jsonObj.pageStats.imageResponseBytes,
JavascriptResponseBytes = jsonObj.pageStats.javascriptResponseBytes,
OtherResponseBytes = jsonObj.pageStats.otherResponseBytes,
NumberJsResources = jsonObj.pageStats.numberJsResources,
NumberCssResources = jsonObj.pageStats.numberCssResources,
};
return CreateOutputString(psiResp);
}
}
static async Task WriteCharacters(IEnumerable<string> inputs, string outputFilePath)
{
using (StreamWriter fileWriter = new StreamWriter(outputFilePath))
{
await fileWriter.WriteLineAsync(TABLE_HEADER);
foreach (var input in inputs)
{
await fileWriter.WriteLineAsync(input);
}
}
}
private static string CreateOutputString(PsiResponse psiResponse)
{
var stringToWrite = "";
foreach (var prop in psiResponse.GetType().GetProperties())
{
stringToWrite += $"{prop.GetValue(psiResponse, null)},";
}
Console.WriteLine(stringToWrite);
return stringToWrite;
}
var resultTask = Task.WhenAll(
inputLines.Select(line => CallPsiForPrimaryStats(line)).ToArray());
static void Main(string[] args) { MainAsync(args).Wait(); }
static async Task MainAsync(string[] args)
{
...
var tasks = inputLines.Select(line => CallPsiForPrimaryStats(line));
var outputCache = await Task.WhenAll(tasks);
await WriteCharacters(outputCache, outputFilePath);
...
private static async Task<string> CallPsiForPrimaryStats(string url)
{
...
Task<WebResponse> task = Task.Factory.FromAsync(
myReq.BeginGetResponse,
myReq.EndGetResponse,
(object)null);
var result = await task;
return ReadStreamFromResponse(result);
}