微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

异步委托 EndInvoke 终止循环早于预期

如何解决异步委托 EndInvoke 终止循环早于预期

我在斐波那契方法上运行委托异步回调模式。此静态方法包含一个循环,其中线程休眠 300 毫秒以打印出后台线程池 ID。不幸的是,在我的 FibCompleted() 中,EndInvoke 方法正在终止我的进程。任何提示都会有所帮助。 谢谢。

public delegate int FibPointer(int x); // FibbonaciSequence() pointer

class Program
{
    static void Main(string[] args)
    {
        // fibonacci Length
        int fibLength = 8;

        // point delegate to method
        FibPointer fb = new FibPointer(FibonacciSequence);
        IAsyncResult iftAR = fb.BeginInvoke(
            fibLen,new AsyncCallback(FibCompleted),null);

        Console.WriteLine("Fibonacci process Now running on thread {0}\n",Thread.CurrentThread.ManagedThreadId);

        int count = 0;
        while (!iftAR.IsCompleted) // completion occurs when userIN length is reached
        {
            // run fib sequence. 
            Console.WriteLine("{0}",FibonacciSequence(count));
            count++;
        }
        Console.ReadKey();
    }

    static int FibonacciSequence(int num)
    {
        int num1 = 0,num2 = 1,res = 0;

        if (num == 0) return 0;
        if (num == 1) return 1;

        for (int i = 0; i < num; i++)
        {
            res = num1 + num2;
            num1 = num2;
            num2 = res;

            Thread.Sleep(300);
            // track background thread from pool
            Console.WriteLine("Working on thread: {0}",Thread.CurrentThread.ManagedThreadId);
        }
        return res;
    }

    static void FibCompleted(IAsyncResult ar)
    {
        Console.WriteLine("\nFib Sequence Completed.");

        // retrieve result 
        AsyncResult res = (AsyncResult)ar;
        //FibPointer fp = ar.AsyncState as FibPointer;
        FibPointer fp = res.AsyncDelegate as FibPointer;

        // call EndInvoke to grab results
        string returnVal = fp.EndInvoke(ar).ToString();
        Console.WriteLine("\nreturn val is: {0}",returnVal);
    }
}

解决方法

如果您必须使用纯 APM。下面是它的一个例子。

void Main()
{
    // fibonacci Length
    int fibLength = 8;

    // point delegate to method
    Func<int,int> fb = FibonacciSequence;
    var completedEvent = new System.Threading.AutoResetEvent(false);
    var iftAR = fb.BeginInvoke(fibLength,FibCompleted,completedEvent);

    completedEvent.WaitOne();
    var result = fb.EndInvoke(iftAR);
    Console.WriteLine("Fibonacci process now running on thread {0}\n",Thread.CurrentThread.ManagedThreadId);
    Console.WriteLine(result);
}

static int FibonacciSequence(int num)
{
    int num1 = 0,num2 = 1,res = 0;

    if (num == 0) return 0;
    if (num == 1) return 1;

    for (int i = 0; i < num; i++)
    {
        res = num1 + num2;
        num1 = num2;
        num2 = res;

        Thread.Sleep(300);
        // track background thread from pool
        Console.WriteLine("Working on thread: {0}",Thread.CurrentThread.ManagedThreadId);
    }
    return res;
}

static void FibCompleted(IAsyncResult ar)
{
    var completedEvent = (AutoResetEvent)ar.AsyncState;
    completedEvent.Set();
}

不过。没有人再使用纯 APM。 APM 被 EAP 取代,EAP 又被 TAP 取代。

我建议您改为学习 TAP。它要简单得多。要将 APM 代码调整为 TAP,您可以使用 TaskFactory 辅助函数。

async Task Main()
{
    // fibonacci Length
    int fibLength = 8;

    // point delegate to method
    Func<int,int> fb = FibonacciSequence;
    
    var result = await Task.Factory.FromAsync (fb.BeginInvoke,fb.EndInvoke,fibLength,null);
    
    Console.WriteLine("Fibonacci process now running on thread {0}\n",Thread.CurrentThread.ManagedThreadId);
    }
    return res;
}

但是,大多数人只会在 TAP 中工作。看起来像这样。

 async Task Main()
{
    // fibonacci Length
    int fibLength = 8;  
    var result = await FibonacciSequence(fibLength);
    
    Console.WriteLine("Fibonacci process now running on thread {0}\n",Thread.CurrentThread.ManagedThreadId);
    Console.WriteLine(result);
}

static Task<int> FibonacciSequence(int num)
{
    // Run computationally intensive work on thread pool.
    return Task.Run(() =>
    {
        int num1 = 0,res = 0;

        if (num == 0) return 0;
        if (num == 1) return 1;

        for (int i = 0; i < num; i++)
        {
            res = num1 + num2;
            num1 = num2;
            num2 = res;

            Thread.Sleep(300);
            // track background thread from pool
            Console.WriteLine("Working on thread: {0}",Thread.CurrentThread.ManagedThreadId);
        }
        return res;
    });
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。