[英]C# in Unity: Calling Promise Style Async method without Blocking the Main Thread
[英]Example of an Async Method that uses the main thread without blocking it.c#
在18#Concurrency in C#Cookbook中,Stephen Cleary定义了异步编程:“一种使用期货或回调来避免不必要线程的并发形式。” 但在代码中,所有异步方法都使用多线程(线程池)。 同一个请给我一个异步方法的例子,它使用主线程而不阻塞它。
例如,考虑一种发送一些http请求并为您提供一些http响应的方法。 如果这个方法是同步的(例如WebRequest.GetResponse()
)那么由于网络延迟,这个方法只会等待90%的时间,因此执行此方法的线程只会睡眠并且什么都不做。
当您使用异步方法(例如HttpClient.PostAsync()
)并等待结果时,调用方法以第一个await
结束,因此调用线程可以自由处理其他工作或可以返回到ThreadPool。 收到您的http响应后,您的工作将恢复。
将继续运行的线程取决于SynchronizationContext
。 因此,如果您从UI线程运行并等待Async方法,则继续将在UI线程上运行。 如果您从后台线程运行并等待异步方法,则继续将在某些ThreadPool线程上运行。
async void button_click(object sender, EventArgs args)
{
_button.Enabled = false; // this is invoked on main thread
var response = await _httpClient.PostAsync(request);
// you will not block main thread and your UI will be responsive
// also you won't occupy ThreadPool thread for all the time to get the response
ProcessResponse(response); // this is invoked on main thread
}
一些Async方法只会在后台运行并占用后台线程,因为它们需要完成所有时间,而有些(IO基本上)则不会。
考虑这个简单的Windows窗体程序:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
GetPoint();
}
public async void GetPoint()
{
var point = await RetrivePointAsync();
MessageBox.Show(point.ToString());
}
public Task<Point> RetrivePointAsync()
{
return Task.Factory.FromAsync<Point>(
(callback, state) => new Handler(this, callback),
x => ((Handler)x).Point, null);
}
}
class Handler : IAsyncResult
{
AsyncCallback _calback;
public Point Point { get; set; }
public object AsyncState { get { return null; } }
public bool CompletedSynchronously { get { return false; } }
public bool IsCompleted { get; set; }
public WaitHandle AsyncWaitHandle { get { return null; } }
public Handler(Control control, AsyncCallback calback)
{
_calback = calback;
control.MouseDown += control_MouseDown;
}
void control_MouseDown(object sender, MouseEventArgs e)
{
Point = e.Location;
IsCompleted = true;
_calback(this);
}
}
如您所见,没有创建新线程来创建异步方法。 我的自定义处理程序只是将鼠标按下事件包装在窗体上。
并非所有异步方法都需要专用线程。 通常,等待I / O完成的那些不一定需要线程。
TaskCompletionSource允许这样的场景
这是“CLR via C#”一书的例子:
private static async Task<String> IssueClientRequestAsync(String serverName, String message) {
using (var pipe = new NamedPipeClientStream(serverName, "PipeName", PipeDirection.InOut,
PipeOptions.Asynchronous | PipeOptions.WriteThrough)) {
pipe.Connect(); // Must Connect before setting ReadMode
pipe.ReadMode = PipeTransmissionMode.Message;
// Asynchronously send data to the server
Byte[] request = Encoding.UTF8.GetBytes(message);
await pipe.WriteAsync(request, 0, request.Length);
// Asynchronously read the server's response
Byte[] response = new Byte[1000];
Int32 bytesRead = await pipe.ReadAsync(response, 0, response.Length);
return Encoding.UTF8.GetString(response, 0, bytesRead);
} // Close the pipe
}
这里执行线程在WriteAsync
调用之后WriteAsync
。 在网络驱动程序完成其工作后,执行将继续执行直到ReadAsync,此时线程将再次释放,直到读取数据。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.