异步委托 学习笔记

System.Windows.Forms.Timer  一直执行在主线程上(即UI线程上)

1、定义一个委托

public delegate int DoSomethingDelegate(int input);

2、定义一个类,类中的方法同委托匹配签名

public class MyObject
{
public int DoubleNumber(int input)
{
return input * 2;
}
}

3、创建一个委托,指向类的方法

MyObject myObj = new MyObject();
// Create a delegate that points to the myObj.DoubleNumber() method.
DoSomethingDelegate doSomething = new DoSomethingDelegate(myObj.DoubleNumber);
// Call the myObj.DoubleNumber() method through the delegate.
int doubleValue = doSomething(12);
What you may not realize is that delegates

直接调用委托方法是,实际使用的是Invoke方法,此方法同步执行相关函数。

另外还有一个BeginInvoke方法,用于异步执行相关函数

IAsyncResult async = doSomething.BeginInvoke(12, null, null);

但是并不返回函数的执行结果。  参数为原始参数+回调对象+状态对象。

前面的例子用异步方法重写后:

MyObject myObj = new MyObject();
// Create a delegate that points to the myObj.DoubleNumber() method.
DoSomethingDelegate doSomething = new DoSomethingDelegate(myObj.DoubleNumber);
// Start the myObj.DoubleNumber() method on another thread.
IAsyncResult async = doSomething.BeginInvoke(originalValue, null, null);  //返回一个IAsyncResult对象。
// (Do something else here while myObj.DoubleNumber() is executing.)
// Retrieve the results, and wait (synchronously) if they're still not ready.
int doubleValue = doSomething.EndInvoke(async);  //通过IAsyncResult对象获取值。

当你调用一个异步方法时,Clr调用了它的线程池中的线程来使用,这个线程池大小一般为单cpu,25个线程。

轮询和回调

当你调用EndInvoke()时,调用成为同步。就是说如果调用没有返回,程序需要等待。

可以使用IAsyncResult.IsCompleted属性来进行查询

IAsyncResult async = doSomething.BeginInvoke(12, null, null);
// Loop until the method is complete.
while (!async.IsCompleted)
{
// Do a small piece of work here.
}
int doubleValue = doSomething.EndInvoke(async);

效率不是很高。

一个更好的选择是使用回调方法。

//回调方法使用IAsyncResult对象作为参数

private void MyCallback(IAsyncResult async)
{ ... }

回调方法的使用

doSomething.BeginInvoke(12, new AsyncCallback(this.MyCallback), null);

回调方法不知道他是被谁触发的,就是说如果这个回调方法对应多个异步操作,它就不知道是哪个操作完成了。

为了取消这个限制,可以给BeginInvoke方法的最后一个参数赋值

然后通过 IAsyncResult.AsyncState 获取

一个有用的技巧是,是使用委托对象作为状态对象

doSomething.BeginInvoke(originalValue,
new AsyncCallback(this.MyCallback), doSomething);

回调方法如下:

private void MyCallback(IAsyncResult async)
{
// Retrieve the delegate.
DoSomethingDelegate doSomething = (DoSomethingDelegate)async.AsyncState;
// Use it to retrieve the result.
int doubleValue = doSomething.EndInvoke(async);
// (Do something with the retrieved information.)
}

回调方法同异步执行方法在同一个线程中,而不是在主线程(ui线程)中。

Windows窗体中的一个示例

代码1:

public class Worker
{
public static int[] FindPrimes(int fromNumber, int toNumber)
{
// Find the primes between fromNumber and toNumber,
// and return them as an array of integers.
}
}

代码2:

private void cmdFind_Click(object sender, EventArgs e)
{
this.UseWaitCursor = true;
txtResults.Text = "";
lblTimeTaken.Text = "";
// Get the search range.
int from, to;
if (!Int32.TryParse(txtFrom.Text, out from))
{
MessageBox.Show("Invalid From value.");
return;
}
if (!Int32.TryParse(txtTo.Text, out to))
{
MessageBox.Show("Invalid To value.");
return;
}
// Start the search for primes and wait.
DateTime startTime = DateTime.Now;
int[] primes = Worker.FindPrimes(from, to);
// Display the time for the call to complete.
lblTimeTaken.Text =
DateTime.Now.Subtract(startTime).TotalSeconds.ToString();
// Paste the list of primes together into one long string.
StringBuilder sb = new StringBuilder();
foreach (int prime in primes)
{sb.Append(prime.ToString());
sb.Append(" ");
}
txtResults.Text = sb.ToString();
this.UseWaitCursor = false;
}

此时,执行过程中,界面无法操作。

异步执行:

代码1:执行异步操作,并更新界面

private void CallAsyncWorker(int from, int to)
{
// Start the search for primes and wait.
DateTime startTime = DateTime.Now;
int[] primes = Worker.FindPrimes(from, to);

// Calculate the time for the call to complete.
TimeSpan timeTaken = DateTime.Now.Subtract(startTime);
// Paste the list of primes together into one long string.
StringBuilder sb = new StringBuilder();
foreach (int prime in primes)
{
sb.Append(prime.ToString());
sb.Append(" ");
}
// Use the Control.Invoke() method of the current form,
// which is owned by the same thread as the rest of the controls.

//在异步执行方法中直接更新结果,没有使用回调函数等。
this.Invoke(new UpdateFormDelegate(UpdateForm),
new object[] {timeTaken, sb.ToString()} );
}

代码2:

private delegate void CallAsyncWorkerDelegate(int from, int to);

代码3:

private void cmdFind_Click(object sender, EventArgs e)
{
// Disable the button.
cmdFind.Enabled = false;
txtResults.Text = "";
lblTimeTaken.Text = "";
// Get the search range.
int from, to;
if (!Int32.TryParse(txtFrom.Text, out from))
{
MessageBox.Show("Invalid From value.");
return;
}
if (!Int32.TryParse(txtTo.Text, out to))
{
MessageBox.Show("Invalid To value.");
return;
}
// Start the search for primes on another thread.
CallAsyncWorkerDelegate doWork = new
CallAsyncWorkerDelegate(CallAsyncWorker);
doWork.BeginInvoke(from, to, null, null);
}

代码4

private delegate void UpdateFormDelegate(TimeSpan timeTaken, string primeList);

代码5


private void UpdateForm(TimeSpan timeTaken, string primeList)
{
lblTimeTaken.Text = timeTaken.TotalSeconds.ToString();
txtResults.Text = primeList;
cmdFind.Enabled = true;
}

原文地址:https://www.cnblogs.com/wenjie/p/3034844.html