【问题标题】:Async Task .Net 4.5异步任务.Net 4.5
【发布时间】:2014-12-19 00:10:47
【问题描述】:

我需要一个函数 A 来启动一个运行时间较长的异步方法函数 B(包括 Web 服务调用)。

即使函数 B 尚未返回,函数 A 也应该返回。

函数 B 不返回任何数据,即使它调用的函数 A 返回了也应该执行

使用 .Net 4.5 C#,最好的代码是什么,你能预见任何线程问题吗?

.net 上有很多示例,但要找到目的代码并不是那么简单。

【问题讨论】:

    标签: .net multithreading asynchronous


    【解决方案1】:

    即使函数 B 尚未返回,函数 A 也应该返回。

    在这种情况下,关键是您不应该在await 上调用B

    启动一个运行时间较长的异步方法函数 B(包括 Web 服务调用)。

    一般来说,如果大部分操作是 Web 服务调用,您应该使用Task.Run。 Task.Run 将在后台线程上执行工作,这可能不是必需的,因为您可以使用异步 IO。

    相反,创建一个async Task B() 方法,在方法中使用正常的await 机制,然后调用它。默认情况下,这会导致编译器警告,但您可以通过创建一个记录发生的异常的FireAndForget 扩展方法来解决此问题。

    这可以很简单:

    public static async void FireAndForget(this Task task)
    {
        try
        {
            await task;
        }
        catch (Exception e)
        {
            // Log the exception
        }
    }
    

    这还提供了B() 中发生的日志记录问题的好处。

    【讨论】:

    • 能够登录的好处是很大的好处!
    • Reed,我正在使用您的扩展方法,但它只是挂在等待任务上。我是否按预期使用它? var t = new Task( () => DoStuff() t.FireAndForget();
    • @STeveWard 通常,使用Task.Run 而不是new Task - 你不需要调用 start
    【解决方案2】:

    最简单的方法是使用Task.Run,它在一个新线程上执行一个动作:

    public void A()
    {
        // Do something...
    
        Task.Run(B);
        // or, if you need to pass arguments to B:
        // Task.Run(() => B(x, y, z));
    
        // Do something else...
    }
    
    public void B()
    {
        // Do something...
    }
    

    注意不要让 B 抛出任何异常,否则会导致进程崩溃。

    【讨论】:

    • 那么很简单!即使 A 在 B 完成之前返回,这也应该有效?
    • @SteveWard,是的; Task.Run 立即返回,而 B 继续在单独的线程上运行。
    • 我认为这不一定是一个很好的做法,特别是因为 OP 指出他们正在使用 Web 服务调用(异步 IO)......
    • @ReedCopsey,好吧,这取决于 B 是如何实现的;如果它使用异步调用,则在新线程上运行它没有任何好处,但如果它只进行同步调用,则将工作卸载到新线程将防止 UI 冻结。
    • 实际上,对 Web 服务的异步调用并不能保证它不会阻塞,因为某些操作是在 .NET 的 HTTP 堆栈中同步完成的(例如 DNS 解析)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-29
    • 1970-01-01
    • 2012-09-02
    相关资源
    最近更新 更多