Async Delegate EndInvoke 比预期更早终止循环

Async Delegate EndInvoke terminating loop earlier than expected

我是 运行 斐波那契方法上的委托异步回调模式。这个静态方法包含一个循环,其中线程休眠 300ms 以打印出后台线程池 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);
    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;
}

然而,大多数人只会在 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, 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;
    });
}