C#async和Java ExecutorService之间的差异

Chi*_*Lan 14 c# java future async-await

C#有一个很酷的新功能

public Task<string> async f()
{
    string r = LongCompute();
    return r;
}
Run Code Online (Sandbox Code Playgroud)

但并不等同于

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

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

怎么样等待?这相当于只调用get

string s = await f();
Run Code Online (Sandbox Code Playgroud)

就像

String s = f().get();
Run Code Online (Sandbox Code Playgroud)

C#还有什么,或者它确实只是Java版本的语法糖?(我不是C#guru,所以我可能会遗漏一些东西).

Jon*_*eet 31

不,await不是像刚才打电话get().有相当多吧.

当您await在C#中使用表达式时,编译器会有效地创建一个延续,因此如果等待尚未完成,则该方法可以立即返回,并且仅在完成时继续处理.延续将在适当的上下文中运行 - 因此,如果您在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); 
}
Run Code Online (Sandbox Code Playgroud)

最终,它的所有语法糖,但很多比你出什么样的糖更复杂.

网上已有很多详细信息.例如:

  • @ Chi-Lan:不是。假设您有一台要实施长时间轮询的服务器,因此可能有成千上万的活动连接。那时,您*确实*不想要每个请求线程模型,因此您不能阻塞等待“任何触发响应的事件”。因此,您需要*某种*的延续机制-C#5中的语言支持使这一点非常简单;它使您可以编写看起来和感觉像我们比较擅长但具有异步属性的同步代码的代码。 (2认同)

Ale*_*sky 11

乔恩没有解释真正的观点.

Java ExecutorService是基于线程的,而C#await可以说是基于光纤.

两者都允许多任务处理,其在并发功能(即,"同时"运行的功能)之间分割计算资源.第一种多任务被称为先发制人,而第二个合作社.从历史上看,先发制人的多任务处理被认为更先进,更优于合作.实际上,在先发制人的多任务处理被消费者操作系统支持之前,计算机确实很糟糕.但是,抢先式多任务处理有其缺点.它可能很难编程,并且它使用更多的内存.

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

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

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

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

回应Jon Skeet:Continuation(因为调用光纤的用户区实现机制)是非平凡的,但线程的实现并不复杂.Jon可能已被抛弃,因为线程背后的算法是在OS中而不是在编译器或.NET运行时中.

  • 谢谢您-20年的Java和3-4年的C#,我无法对“幕后”进行深入的分析。 (2认同)

vit*_*ilo 5

只是为了扩展乔恩·斯凯特(Jon Skeet)的正确答案。

没有Java模拟的C#等待表达式。悬停器,某些Java框架具有相同的功能:

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