14

C# 有一个很酷的新特性

public Task<string> async f()
{
    string r = LongCompute();
    return r;
}

但这不等于

public Future<String> f() {
    return Globals.executorService.submit(new Callable<String>() {
        public String call() throws Exception {
            String r = longCompute();
            return r;
        }
    });
}

在 Java 中,您可以更灵活地选择任务将在其中运行的线程池。

等待呢?相当于只调用get

string s = await f();

就像

String s = f().get();

C# 是否还有更多内容,或者它确实只是 Java 版本的语法糖?(我不是 C# 大师,所以我可能会遗漏一些东西)。

4

3 回答 3

30

不,不像await只是打电话。还有更多get()

当您在 C# 中使用await表达式时,编译器有效地创建了一个延续,因此如果 awaitable 尚未完成,该方法可以立即返回,并仅在完成后继续处理。延续将在适当的上下文中运行 - 因此,如果您在await表达式之前位于 UI 线程上,则之后您将在 UI 线程上继续,但在等待结果时不会阻塞 UI 线程。例如:

public async void HandleButtonClick(object sender, EventArgs e)
{
    // All of this method will run in the UI thread, which it needs
    // to as it touches the UI... however, it won't block when it does
    // the web operation.

    string url = urlTextBox.Text;
    WebClient client = new WebClient();
    string webText = await client.DownloadStringTaskAsync(url);

    // Continuation... automatically called in the UI thread, with appropriate
    // context (local variables etc) which we used earlier.
    sizeTextBox.Text = string.Format("{0}: {1}", url, webText.Length); 
}

最终它都是语法糖,但你展示的要复杂得多。

网上已经有很多详细的信息了。例如:

于 2012-03-28T08:59:03.590 回答
12

乔恩没有解释真正的意义

JavaExecutorService是基于线程的,而 C#await可以说是基于Fiber的。

两者都允许多任务处理,这在并发功能(即“同时”运行的功能)之间分割计算资源。第一种多任务处理称为先发制人,而第二种称为合作。从历史上看,抢先式多任务处理被认为比合作更先进和优越。事实上,在消费者操作系统支持抢先式多任务处理之前,计算机真的很烂。然而,抢先式多任务处理也有其缺点。它可能很难编程,而且它使用更多的内存。

两者的主要区别在于抢占式多任务允许运行时(通常是操作系统本身)随时停止任何功能并启动不同的功能(并在不同的 CPU 上同时运行它们)。同时,协同多任务处理需要运行功能结束或自动暂停。我们大多数人都熟悉多线程形式的抢占式多任务,以及与之相伴的那种仔细的编程。很少有人熟悉协作多任务处理,现在通常称为纤程或协程(在这种情况下,它是在抢占式操作系统线程内的用户空间中实现的)。

无论如何,关键是ExecutorServiceandawait不能直接比较,并且await通常不优于真正的多线程(除了它具有很好的语法糖)。C# 包含await(并基于协作多任务处理)的原因是平台上的主要 GUI 工具包不是为多线程而设计的,重构它们以支持并发将需要大量工作。协作式多任务处理对于 UI 来说效果很好,因为大多数事件处理程序都很短并且可以串行执行。await通过让长事件处理程序暂停自己并在渲染函数有机会运行后恢复来扩展事件循环的概念。所有这些都发生在单个 CPU 内核上的单个线程中。

他们找到共同点的地方在于,它们都是多任务处理的形式,Future.get并且await Task都是同步的形式。

正如所料,C# 并非没有对线程和线程池的良好支持。同样,Java 在许多库中包含纤程/协同例程/异步,例如 Servlet 3.0 和javafx.concurrent.Task.

作为对 Jon Skeet 的回应:Continuation(因为纤维的用户态实现机制被称为)是不平凡的,但线程在其实现中同样复杂。Jon 可能被抛弃了,因为线程背后的算法在操作系统中,而不是在编译器或 .NET 运行时中。

于 2014-07-04T06:24:32.950 回答
5

只是为了扩展正确的 Jon Skeet 的答案。

这不是 C# await 表达式的 Java 模拟。Hoverer,一些 Java 框架具有相同的功能:

事实上,它们即时生成例程或状态机代码。

于 2013-07-07T16:05:29.220 回答