C# 异步多线程实现(一)异步委托——Action和Func

可参考:

CSharp中委托(一)委托、匿名函数、lambda表达式、多播委托、窗体传值、泛型委托》一文中的窗体传值。

如果你采用了.NetCore,经实测采用BeginInvoke无法启动。

切换到.NetFramework下可以使用。

结论

  • Action委托类型变量接受要异步执行的方法 ,然后BeginInvoke
  • BeginInvoke是新启线程异步调用。Invoke是同步执行。
  • Action类型委托只接受没有返回值的方法,如果有返回值那就用Func委托类型。
  • BeginInvoke有两个必须的参数放在最后。
    • 倒数第二个参数是可以放回调函数的委托:线程执行完需要做的事。
    • 倒数第一个参数是可以给回调函数传参数。
  • BeginInvoke返回一个IAsyncResult类型,可以通过等待句柄AsyncWaitHandle判断是否执行结束。
  • 可以通过EndInvoke接受线程结果(方法带返回值)。

参考代码如下:

static void Main(string[] args)
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    Action t1 = Test1;
    Action<int> t2 = Test2;
    Action t3 = Test3;
    Func<int, int, int> t4 = Test4;
    Console.WriteLine("主函数主线程。");
    IAsyncResult ar = t1.BeginInvoke(null, null);
    // 判断异步调用是否结束。第一种方式。
    //while (ar.IsCompleted == false)
    //{
    //    Console.Write("=====");
    //    Thread.Sleep(20);
    //}
    //t1.EndInvoke(ar); // 取得异步线程的返回值。
    t2.BeginInvoke(666, null, null);
    t3.BeginInvoke(null, null);
    IAsyncResult ar4 = t4.BeginInvoke(5, 5, null, null);
    int res = t4.EndInvoke(ar4);
    Console.WriteLine(@"Test4 输出结果:{0}", res);
    sw.Stop();
    string time = sw.Elapsed.ToString();
    Console.WriteLine(time);

    Func<int, int, int> t6 = Test4;
    IAsyncResult ar5 = t6.BeginInvoke(5, 5, null, null);

    // 添加线程结束检测:等待句柄。第二种方式。
    bool isEnd = ar5.AsyncWaitHandle.WaitOne(1000); // 如果1000毫秒内运行结束,返回True。
    if (isEnd)
    {
        // 需要注释掉上面的t4.EndInvoke(ar4)
        int res2 = t6.EndInvoke(ar5);
        Console.WriteLine(@"如果执行完了,接受输出。{0}",res2);
    }
    // 还可以通过回调函数来检测执行。第三种方式。
    IAsyncResult ar6 = t4.BeginInvoke(5, 6, OnCallBack, t4);
    // 倒数第二个参数是委托类型,可以写回调函数:即:线程执行完需要做的事。
    // 倒数第一个参数是需要给回调函数传入的参数。我们可以把t4传入。

    // 使用lambda表达式来写上面的异步调用。第四种。
    Func<int, int, int> t5 = Test4;
    t5.BeginInvoke(5, 7, ar66 =>
    {
        int res66 = t5.EndInvoke(ar66);
        Console.WriteLine(res66 + "在lambda表达式中取得");
    }, null);


    Console.ReadLine();
}

private static void OnCallBack(IAsyncResult ar)
{
    Console.WriteLine("回调函数回答:子线程结束。");
    // 在回调函数中取得参数。获取EndInvoke的结果。
    Func<int, int, int> arC = ar.AsyncState as Func<int, int, int>;
    int res = arC.EndInvoke(ar);
    Console.WriteLine("在回调函数中,使用委托的本身,调用委托返回值。");
}

static void Test1()
{
    Console.WriteLine(@"Test1启动ID, 线程ID为:{0}",Thread.CurrentThread.ManagedThreadId);
    Thread.Sleep(1000);
    Console.WriteLine(@"Test1结束ID, 线程ID为:{0}", Thread.CurrentThread.ManagedThreadId);
}
static void Test2(int num)
{
    Console.WriteLine("Test2启动ID, 线程ID为:{0}", Thread.CurrentThread.ManagedThreadId);
    Thread.Sleep(900);
    Console.WriteLine("Test2中处理的数字{0}", num);
    Console.WriteLine("Test2结束ID, 线程ID为:{0}", Thread.CurrentThread.ManagedThreadId);
}
static void Test3()
{
    Console.WriteLine("Test3启动ID, 线程ID为:{0}", Thread.CurrentThread.ManagedThreadId);
    Thread.Sleep(1100);
    Console.WriteLine("Test3结束ID, 线程ID为:{0}", Thread.CurrentThread.ManagedThreadId);
}

static int Test4(int a, int b)
{
    Console.WriteLine("Test4被启动, 线程ID为:{0}", Thread.CurrentThread.ManagedThreadId);
    Thread.Sleep(500);
    Console.WriteLine("Test4执行完毕, 线程ID为:{0}", Thread.CurrentThread.ManagedThreadId);
    return a + b * 10086;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值