C# 如何以正确的方式实现我的异步方法?

C# 如何以正确的方式实现我的异步方法?,c#,async-await,c#-5.0,C#,Async Await,C# 5.0,我想知道实现我自己的异步方法的最佳方式是什么。我读过,它说将同步方法包装到任务中并将其用作异步方法不是一个好主意,因为这样会使用其他线程并使用更多资源,这是我们希望避免使用异步方法的原因 在本文中使用TaskCompletionSource,但我不知道如何使用它。TaskCompletionSource的目的是什么?在另一个async方法中调用一个方法(使用.NET 5.0async关键字)对我来说很好。我不确定我是否完全理解你的问题,但举下面一个简单的例子。要显示起始int和计数之间的素数,我

我想知道实现我自己的异步方法的最佳方式是什么。我读过,它说将同步方法包装到任务中并将其用作异步方法不是一个好主意,因为这样会使用其他线程并使用更多资源,这是我们希望避免使用异步方法的原因


在本文中使用TaskCompletionSource,但我不知道如何使用它。TaskCompletionSource的目的是什么?

在另一个
async
方法中调用一个方法(使用.NET 5.0
async
关键字)对我来说很好。我不确定我是否完全理解你的问题,但举下面一个简单的例子。要显示起始
int
和计数之间的素数,我们可以编写

async void DisplayPrimes()
{
    int result = await GetPrimesCountAsync(2, 10000);
    Console.WriteLine(result);
}
在哪里

Task<int> GetPrimesCountAsync(int start, int count)
{
    return Task.Run(() => 
        ParrallelEnumerable.Range(start, count).COunt(n => 
            Enumerable.Range(2, (int)Math.Sqrt(n) - 1).All(i => n % i > 0)));
}
我希望这有帮助


编辑。因此,为了避免任务阻塞(因为您没有发布代码,所以很难判断您的情况),您需要将要创建的
async
流程提升到“一个级别”

private async Task<bool> TestAsync()
{
    return await Task.Run(() => 
    {
        // Do stuff non-blocking.            
        return true;
    }).ConfigureAwait(continueOnCapturedContext:false);
}
专用异步任务TestAsync()
{
返回等待任务。运行(()=>
{
//做一些非阻塞的事情。
返回true;
}).ConfigureAwait(continueOnCapturedContext:false);
}
TestAsync
这里可以通过在线程池线程而不是UI上下文上执行其“return”语句来完成。这将立即返回给调用者,但请注意,如果继续使用
Task.Result
,则任何异常都会被包装在一个
聚合异常中,您必须相应地处理该异常


可以找到一个很好的解释。在进入
async
/
wait
之前,我建议您先学习C#4.0任务,因为这将使您更好地理解并发性

编写
async
方法的最佳资源是。该文件中的大部分信息现在都已公开

如果你想要一个较短(但仍然完整)的教程,我推荐我自己的,还有其他几个教程。一旦您了解了一点
async
,下一个好的资源就是

Channel9上还有大量的
async
视频。当它还是一个CTP时,他们中的许多人(大多数?)讨论了
async
,但当它投入生产时,很少进行设计更改


为了回答您的特定问题,
TaskCompletionSource
用于围绕现有异步操作(例如,I/O操作、计时器或事件)创建一个
Task
包装器。您不能在由
TaskCompletionSource
创建的
任务中执行代码;您应该使用
Task.Run
来执行
任务中的代码

我正确地理解了这篇文章,问题是如果我使用Tas.Run,我会创建一个新线程,这会使用更多的资源,所以目标不是为异步方法使用新线程。问题是,到目前为止,我不知道如何在没有task.Run的情况下实现异步方法,而不是阻止UI。这篇文章使用了TaskCompletionSource,它不会创建新线程,但我不知道如何正确使用它。请参阅编辑了解更多说明。听起来你误解了运行“异步”的概念,因为它本质上总是涉及第二个线程。如果您对创建/删除额外的线程感到不舒服,您可以创建一个额外的线程来等待处理(没有繁忙的循环!),本质上就是重用它的资源。缺点是,每次运行只能处理一个异步请求,但它可以工作。@Mario:“基本上总是涉及第二个线程。”我不同意这种说法。只有异步代码需要另一个线程;所有其他异步操作(I/O、计时器、事件)都没有。直到现在,我一直遵循您在las示例中所说的方式。我使用了一个sync方法,因为它可能是复杂的代码,而且可读性更高。但通过这种方式,就是在任务中包装一个sync方法来创建我的异步方法。这是本文作者试图避免的吗?但是如果我使用task.Run,我会创建一个新线程,如果我没有错,这会创建一个新线程,这是我们想要避免的,因为使用更多的资源和可伸缩性更差。是否可以在不创建新线程的情况下执行任务中的代码?代码还将在哪里运行?True。然后,如果我使用像killercam这样的代码,那就是我正在做的,这与在任务中包装一个同步方法来创建异步方法是一样的。如果这是真的,在我的文章中,作者说这不是一个好的做法。
private async Task<bool> TestAsync()
{
    return await Task.Run(() => 
    {
        // Do stuff non-blocking.            
        return true;
    }).ConfigureAwait(continueOnCapturedContext:false);
}