• 异步委托 学习笔记


    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;
    }

  • 相关阅读:
    阅读ARm芯片手册 阅读方法
    Linux驱动mmap内存映射
    Linux下inotify的基本使用及注意事项
    网络视频监控与人脸识别
    Linux pci驱动源码
    Verilog语法
    跟着我从零开始入门FPGA(一周入门XXOO系列)-1、Verilog语法
    周立功-我的25年嵌入式生涯
    Linux 进程学习
    [转]MFC下关于“建立空文档失败”问题的分析
  • 原文地址:https://www.cnblogs.com/wenjie/p/3034844.html
Copyright © 2020-2023  润新知