异步/计谋whenall并立即返回计谋、whenall

2023-09-03 06:02:43 作者:一世浮沉

我这个简单的测试code ......(不要打扰怪使用类方法...)

我试图把握任务<> 复杂......我想我有任务℃的了解甚少;>。开始() / 任务<>。结果模式(也许因为它更象是'老' Thread.Start( )?),但只要在我看来,要把握的东西(所以我扔在计谋关键字)......那么所有萦再次: - (

为什么我的code立即返回第一个任务完成后?为什么它不伺候 Task.WhenAll()

 静态BigInteger的因子(BigInteger的因素)
{
    BigInteger的阶乘= 1;
    对于(BigInteger的I = 1; I< =系数;我++)
    {
        阶乘* =我;
    }
    返回阶乘;
}

私有类ChancesToWin
{
    私人诠释_n,_r;

    公共ChancesToWin(INT N,INT读)
    {
        _n = N;
        _r = R;
    }

    私人任务< BigInteger的> CalculateFactAsync(int值)
    {
        返回Task.Factory.StartNew< BigInteger的>(()=>因子(值));
    }

    公共异步任务< BigInteger的> getFactN()
    {
        BigInteger的结果=等待CalculateFactAsync(_n);
        返回结果;
    }

    公共异步任务< BigInteger的> getFactN_R()
    {
        BigInteger的结果=等待CalculateFactAsync(_n  -  _r);
        返回结果;
    }

    公共异步任务< BigInteger的> getFactR()
    {
        BigInteger的结果=等待CalculateFactAsync(_r);
        返回结果;
    }

}

私人异步静态无效TaskBasedChancesToWin_UseClass()
{
    INT N = 69000;
    INT R = 600;

    名单<任务< BigInteger的>>任务=新的名单,其中,任务< BigInteger的>>();

    ChancesToWin CTW =新ChancesToWin(N,R);

    tasks.Add(ctw.getFactN());
    tasks.Add(ctw.getFactN_R());
    tasks.Add(ctw.getFactR());

    //该getFactR()返回第一的另外两个任务...和code出口!
    BigInteger的[]结果=等待Task.WhenAll(任务);

    //我不明白这里!!!!
    BigInteger的机率=结果[0] /结果[1] *结果[2];

    //Debug.WriteLine(chances);
}

静态无效的主要(字串[] args)
{
    TaskBasedChancesToWin_UseClass();
}
 

解决方案

异步方法同步运行,直到第一个计谋,当他们返回控制给调用方​​法,通常返回任务重presenting异步操作的其余部分。 TaskBasedChancesToWin_UseClass 不返回任务,以便调用者不能等待它完成。这就是为什么你不应该异步无效之外使用事件处理程序。

由于不等待您的应用程序结束操作有机会完成之前的操作。

您通常会等待与等待不过既然你不能是异步方法可以阻止同步与等待从任务返回 TaskBasedChancesToWin_UseClass

 异步静态任务TaskBasedChancesToWin_UseClass()
{
    // ...
}

静态无效的主要()
{
    TaskBasedChancesToWin_UseClass()等待()。
}
 
C 怎么调用方法

I have this "simple" test code... (Don't bother the strange use of the Class methods...)

I am trying to grasp the Task<> intricacies... I think I have a little understanding of Task<>.Start()/Task<>.Result pattern (maybe as it resembles more the 'old' Thread.Start()?) but as soon as it seems to me to grasp something (and so I throw in the await keyword)... then all entangles again :-(

Why my code returns immediately after the first task completes? Why it doesn't wait on the Task.WhenAll()?

static BigInteger Factorial(BigInteger factor)
{
    BigInteger factorial = 1;
    for (BigInteger i = 1; i <= factor; i++)
    {
        factorial *= i;
    }
    return factorial;
}

private class ChancesToWin
{
    private int _n, _r;

    public ChancesToWin(int n, int r)
    {
        _n = n;
        _r = r;
    }

    private Task<BigInteger> CalculateFactAsync(int value)
    {
        return Task.Factory.StartNew<BigInteger>(() => Factorial(value));
    }

    public async Task<BigInteger> getFactN()
    {
        BigInteger result = await CalculateFactAsync(_n);
        return result;
    }

    public async Task<BigInteger> getFactN_R()
    {
        BigInteger result = await CalculateFactAsync(_n - _r);
        return result;
    }

    public async Task<BigInteger> getFactR()
    {
        BigInteger result = await CalculateFactAsync(_r);
        return result;
    }

}

private async static void TaskBasedChancesToWin_UseClass()
{
    int n = 69000;
    int r = 600;

    List<Task<BigInteger>> tasks = new List<Task<BigInteger>>();

    ChancesToWin ctw = new ChancesToWin(n, r);

    tasks.Add(ctw.getFactN());
    tasks.Add(ctw.getFactN_R());
    tasks.Add(ctw.getFactR());

    // The getFactR() returns first of the other two tasks... and the code exit!
    BigInteger[] results = await Task.WhenAll(tasks);

    // I don't get here !!!!
    BigInteger chances = results[0] / results[1] * results[2];

    //Debug.WriteLine(chances);
}

static void Main(string[] args)
{
    TaskBasedChancesToWin_UseClass();
}

解决方案

Async methods run synchronously until the first await when they return control to the calling method, usually returning a task representing the rest of the asynchronous operation. TaskBasedChancesToWin_UseClass doesn't return a task so the caller can't wait for it to complete. That's why you shouldn't use async void outside of event handlers.

Since Main doesn't wait for the operation your application ends before the operation had a chance to complete.

You would usually wait with await but since you Main can't be an async method you can block synchronously with Wait on the task returned from TaskBasedChancesToWin_UseClass:

async static Task TaskBasedChancesToWin_UseClass()
{
    // ...
}

static void Main()
{
    TaskBasedChancesToWin_UseClass().Wait();
}