使用哪个 WebClient.OpenRead、OpenReadAsync 或 OpenReadTaskAsync
Which to use, WebClient.OpenRead, OpenReadAsync or OpenReadTaskAsync
我正在尝试了解 WebClient.OpenRead
, WebClient.OpenReadAsync
and WebClient.OpenReadTaskAsync
之间的差异。
貌似在阻塞线程方面有区别,但我不是很了解
你能解释一下不同之处吗?如果你能给我一些例子就太好了(例子不一定是示例代码,但如果你能提供就更好了)
我建议 WebClient
现在或多或少已经过时了,HttpClient
更适合任何面向 .NET Framework 4.5+ 或 .NET Core 的应用程序。请注意后者不会自动抛出 HTTP 错误代码 (400+) 的异常。
如您所说,区别在于线程阻塞行为。第一个 (OpenRead()) 是线程阻塞操作,其他两个不是。例如,假设您达到 google.com 的网络延迟为 300 毫秒。当您执行 var stream = webClient.OpenRead(@"https://www.google.com");
时,您的应用程序在这 300 毫秒内为 "paused",因此直到您的 webClient
return 到 stream
变量的流。这是调用线程阻塞。
当您在 UI 线程中执行此操作时(例如:在按钮单击处理程序中)- 您的应用程序变得冻结并且不响应用户操作。这是 糟糕的 用户体验,所以永远不要在 UI 中调用线程阻塞的东西。这是控制台应用程序的示例:
var address = @"https://www.google.com/";
Console.WriteLine($"Opening stream from {address}");
using (var stream = webClient.OpenRead(address)) // this will block for 300ms
{
Console.WriteLine("Stream is open!");
// some other code
}
第二种方法(OpenReadAsync()) is asynchronous and return nothing immediately after a call, so your thread is not blocked. After awhile (300ms) OpenReadCompleted 事件将由您的 webClient
引发,所有附加的侦听器将逐个处理打开的流。这是一个示例:
public partial class MainForm : Form
{
private WebClient _client = new WebClient();
public MainForm()
{
InitializeComponents();
_client.OpenReadCompleted += OpenReadCompletedHandler;
}
private void ButtonClickHandler(object sender, EventArgs e)
{
_client.OpenReadAsync(@"https://www.google.com/");
}
private void OpenReadCompletedHandler(object sender, OpenReadCompletedEventArgs e)
{
// this event will be raiesed 300ms after 'Button' click
var stream = e.Result; // <- here is your stream
// some other code
}
}
最后一个(OpenReadTaskAsync()) is all about TPL (Task Parallel Library) 和 async/await 关键字。它在 Task
这是 return 通过这种方法编辑的。这是一个示例:
public partial class MainForm : Form
{
private WebClient _client = new WebClient();
public MainForm()
{
InitializeComponents();
}
private async void ButtonClickHandler(object sender, EventArgs e)
{
// after 'await' keyword, execution will be returned from this method immediately
// meanwhile, actual acquiring of 'stream' is running in a background thread
using (var stream = await _client.OpenReadTaskAsync(@"https://www.google.com/"))
{
// after 300ms, this code will be continued in UI thread
// result will be automaticly unpacked to 'stream' variable
// some other code
}
}
}
希望这对您有所帮助。
我正在尝试了解 WebClient.OpenRead
, WebClient.OpenReadAsync
and WebClient.OpenReadTaskAsync
之间的差异。
貌似在阻塞线程方面有区别,但我不是很了解
你能解释一下不同之处吗?如果你能给我一些例子就太好了(例子不一定是示例代码,但如果你能提供就更好了)
我建议 WebClient
现在或多或少已经过时了,HttpClient
更适合任何面向 .NET Framework 4.5+ 或 .NET Core 的应用程序。请注意后者不会自动抛出 HTTP 错误代码 (400+) 的异常。
如您所说,区别在于线程阻塞行为。第一个 (OpenRead()) 是线程阻塞操作,其他两个不是。例如,假设您达到 google.com 的网络延迟为 300 毫秒。当您执行 var stream = webClient.OpenRead(@"https://www.google.com");
时,您的应用程序在这 300 毫秒内为 "paused",因此直到您的 webClient
return 到 stream
变量的流。这是调用线程阻塞。
当您在 UI 线程中执行此操作时(例如:在按钮单击处理程序中)- 您的应用程序变得冻结并且不响应用户操作。这是 糟糕的 用户体验,所以永远不要在 UI 中调用线程阻塞的东西。这是控制台应用程序的示例:
var address = @"https://www.google.com/";
Console.WriteLine($"Opening stream from {address}");
using (var stream = webClient.OpenRead(address)) // this will block for 300ms
{
Console.WriteLine("Stream is open!");
// some other code
}
第二种方法(OpenReadAsync()) is asynchronous and return nothing immediately after a call, so your thread is not blocked. After awhile (300ms) OpenReadCompleted 事件将由您的 webClient
引发,所有附加的侦听器将逐个处理打开的流。这是一个示例:
public partial class MainForm : Form
{
private WebClient _client = new WebClient();
public MainForm()
{
InitializeComponents();
_client.OpenReadCompleted += OpenReadCompletedHandler;
}
private void ButtonClickHandler(object sender, EventArgs e)
{
_client.OpenReadAsync(@"https://www.google.com/");
}
private void OpenReadCompletedHandler(object sender, OpenReadCompletedEventArgs e)
{
// this event will be raiesed 300ms after 'Button' click
var stream = e.Result; // <- here is your stream
// some other code
}
}
最后一个(OpenReadTaskAsync()) is all about TPL (Task Parallel Library) 和 async/await 关键字。它在 Task
这是 return 通过这种方法编辑的。这是一个示例:
public partial class MainForm : Form
{
private WebClient _client = new WebClient();
public MainForm()
{
InitializeComponents();
}
private async void ButtonClickHandler(object sender, EventArgs e)
{
// after 'await' keyword, execution will be returned from this method immediately
// meanwhile, actual acquiring of 'stream' is running in a background thread
using (var stream = await _client.OpenReadTaskAsync(@"https://www.google.com/"))
{
// after 300ms, this code will be continued in UI thread
// result will be automaticly unpacked to 'stream' variable
// some other code
}
}
}
希望这对您有所帮助。