多个网络请求,在等待最后一个响应时启动另一个请求。 C#
Multiple web requests, start another request while waiting for response on last one. C#
我正在尝试从需要很长时间才能加载完整响应(非常长的日志文件)的网站发出多个 Web 请求。我想实现一种方法,该方法将在等待其他请求响应的同时继续创建 Web 请求并加快处理速度。
尝试实现异步等待方法,但我不认为是在创建同时调用,而是 运行 同步调用。我对如何实现异步等待感到很困惑,我看了其他类似的问题但仍然不是很清楚,我怎么能把这段代码改成 运行 async?
这是我的代码:
public static async Task<String> MakeRequestAsync(String url)
{
String responseText = null;
try
{
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Proxy = null;
WebResponse response = request.GetResponse();
Stream responseStream = response.GetResponseStream();
string sr = new StreamReader(responseStream).ReadToEnd();
response.Close();
responseStream.Close();
responseText = sr;
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
return responseText;
}
..
private void button_test_Click(object sender, EventArgs e)
{
for (int n = 0; n < 5; n++) //multiple requests
{
String a = AsyncTest().Result;
}
}
private async Task<String> AsyncTest()
{
String b = await MakeRequestAsync(url);
return b;
}
还有任何关于如何加快此过程的建议都很棒。
None 个 IO 调用是 async
。 WebRequest
也没有 async/await
模式,您可以使用 BeginGetResponse
和 AsyncCallback
获得 async
行为,但还有更好的方法。而是使用 HttpClient
,这是进行 http 调用的推荐方式。
即
public static async Task<String> MakeRequestAsync(string url)
{
using(var client = new HttpClient()) // don't do this, inject it as a singleton
{
using (var response = await client.GetAsync(url)
return await response.Content.ReadAsStringAsync();
}
}
然后将您的 Click
处理程序更改为 async void
:
private async void button_test_Click(object sender, EventArgs e)
{
var tasks = new List<Task<string>>();
for (int n = 0; n < 5; n++) //multiple requests
{
tasks.Add(MakeRequestAsync(url));
}
await Task.WhenAll(tasks); // wait for all of them to complete;
foreach(var task in tasks)
{
var str = await task; // or task.Result, won't block, already completed;
}
}
您应该使用 Microsoft 的 Reactive Framework(又名 Rx)- NuGet System.Reactive
并添加 using System.Reactive.Linq;
- 然后您可以这样做:
var query =
from n in Observable.Range(0, 5)
from r in Observable.Using(
() => new WebClient(),
wc => Observable.Start(() => wc.DownloadString($"{url}{n}")))
select new { n, r };
IDisposable subscription =
query
.ToArray()
.Select(xs => xs.OrderBy(x => x.n).Select(x => x.r).ToArray())
.Subscribe(rs =>
{
/* Do something with the results */
});
都是多线程非阻塞的
如果您不关心返回结果的顺序,那么只需这样做:
var query =
from n in Observable.Range(0, 5)
from r in Observable.Using(
() => new WebClient(),
wc => Observable.Start(() => wc.DownloadString($"{url}{n}")))
select r;
IDisposable subscription =
query
.Subscribe(r =>
{
/* Do something with each result */
});
如果您需要取消查询,调用 subscription.Dispose()
将停止查询。
您可以这样编写 MakeRequestAsync
方法:
public static async Task<String> MakeRequestAsync(String url)
{
return await
Observable.Using(
() => new WebClient(),
wc => Observable.Start(() => wc.DownloadString(url)));
}
我正在尝试从需要很长时间才能加载完整响应(非常长的日志文件)的网站发出多个 Web 请求。我想实现一种方法,该方法将在等待其他请求响应的同时继续创建 Web 请求并加快处理速度。
尝试实现异步等待方法,但我不认为是在创建同时调用,而是 运行 同步调用。我对如何实现异步等待感到很困惑,我看了其他类似的问题但仍然不是很清楚,我怎么能把这段代码改成 运行 async?
这是我的代码:
public static async Task<String> MakeRequestAsync(String url)
{
String responseText = null;
try
{
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Proxy = null;
WebResponse response = request.GetResponse();
Stream responseStream = response.GetResponseStream();
string sr = new StreamReader(responseStream).ReadToEnd();
response.Close();
responseStream.Close();
responseText = sr;
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
return responseText;
}
..
private void button_test_Click(object sender, EventArgs e)
{
for (int n = 0; n < 5; n++) //multiple requests
{
String a = AsyncTest().Result;
}
}
private async Task<String> AsyncTest()
{
String b = await MakeRequestAsync(url);
return b;
}
还有任何关于如何加快此过程的建议都很棒。
None 个 IO 调用是 async
。 WebRequest
也没有 async/await
模式,您可以使用 BeginGetResponse
和 AsyncCallback
获得 async
行为,但还有更好的方法。而是使用 HttpClient
,这是进行 http 调用的推荐方式。
即
public static async Task<String> MakeRequestAsync(string url)
{
using(var client = new HttpClient()) // don't do this, inject it as a singleton
{
using (var response = await client.GetAsync(url)
return await response.Content.ReadAsStringAsync();
}
}
然后将您的 Click
处理程序更改为 async void
:
private async void button_test_Click(object sender, EventArgs e)
{
var tasks = new List<Task<string>>();
for (int n = 0; n < 5; n++) //multiple requests
{
tasks.Add(MakeRequestAsync(url));
}
await Task.WhenAll(tasks); // wait for all of them to complete;
foreach(var task in tasks)
{
var str = await task; // or task.Result, won't block, already completed;
}
}
您应该使用 Microsoft 的 Reactive Framework(又名 Rx)- NuGet System.Reactive
并添加 using System.Reactive.Linq;
- 然后您可以这样做:
var query =
from n in Observable.Range(0, 5)
from r in Observable.Using(
() => new WebClient(),
wc => Observable.Start(() => wc.DownloadString($"{url}{n}")))
select new { n, r };
IDisposable subscription =
query
.ToArray()
.Select(xs => xs.OrderBy(x => x.n).Select(x => x.r).ToArray())
.Subscribe(rs =>
{
/* Do something with the results */
});
都是多线程非阻塞的
如果您不关心返回结果的顺序,那么只需这样做:
var query =
from n in Observable.Range(0, 5)
from r in Observable.Using(
() => new WebClient(),
wc => Observable.Start(() => wc.DownloadString($"{url}{n}")))
select r;
IDisposable subscription =
query
.Subscribe(r =>
{
/* Do something with each result */
});
如果您需要取消查询,调用 subscription.Dispose()
将停止查询。
您可以这样编写 MakeRequestAsync
方法:
public static async Task<String> MakeRequestAsync(String url)
{
return await
Observable.Using(
() => new WebClient(),
wc => Observable.Start(() => wc.DownloadString(url)));
}