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

ジョンは本当の要点を説明しませんでした。

JavaはスレッドExecutorServiceに基づいていますが、C#はファイバーに基づいていると言えます。await

どちらもマルチタスクを可能にし、コンピューティング リソースを並行機能 (つまり、「同時に」実行される機能) に分割します。マルチタスクの最初の種類はプリエンプティブと呼ばれ、2 番目のマルチタスクは協調的と呼ばれます。歴史的に、プリエンプティブ マルチタスキングは協調的よりも高度で優れていると考えられていました。実際、プリエンプティブ マルチタスキングが消費者向けオペレーティング システムでサポートされるようになる前は、コンピューターは本当に最悪でした。ただし、プリエンプティブ マルチタスクには欠点があります。プログラミングが難しくなる可能性があり、より多くのメモリを使用します。

この 2 つの主な違いは、プリエンプティブ マルチタスキングにより、ランタイム (通常はオペレーティング システム自体) が任意の機能をいつでも停止し、別の機能を開始できる (そしてそれらを異なる CPU で同時に実行できる) ことです。一方、協調的なマルチタスクでは、実行中の機能を終了するか、自発的に一時停止する必要があります。私たちのほとんどは、マルチスレッドの形でのプリエンプティブ マルチタスクと、それに伴う慎重なプログラミングに精通しています。現在、ファイバーまたはコルーチンと呼ばれることが多い協調マルチタスクに精通している人はほとんどいません (この場合、プリエンプティブ OS のスレッド内のユーザーランドに実装されます)。

とにかく、要点は、ExecutorServiceawaitは直接比較できるものでawaitはなく、一般に、実際のマルチスレッドよりも優れているわけではありません (優れたシンタックス シュガーを備えていることを除けば)。C# を含めるawait(そしてそれを協調マルチタスクに基づく) 理由は、プラットフォーム上の主要な GUI ツールキットがマルチスレッド用に設計されておらず、並行性をサポートするためにそれらをリファクタリングするのに大量の作業が必要になるためです。ほとんどのイベント ハンドラーは短く、連続して実行できるため、協調マルチタスクは UI に適しています。await長いイベント ハンドラーが一時停止し、レンダリング関数が実行される機会を得た後に再開できるようにすることで、イベント ループの概念を拡張します。これらはすべて、1 つの CPU コアの 1 つのスレッドで発生します。

両者の共通点は、どちらもマルチタスクの形式であり、Future.get両方await Taskとも同期の形式であるということです。

当然のことながら、C# にはスレッドとスレッド プールの適切なサポートがないわけではありません。同様に、Java には、Servlet 3.0 やjavafx.concurrent.Task.

Jon Skeet への回答:継続(ファイバーのユーザーランド実装メカニズムが呼び出されるため) は自明ではありませんが、スレッドの実装はそれほど洗練されていません。スレッドの背後にあるアルゴリズムは、コンパイラや .NET ランタイムではなく OS にあるため、Jon は見捨てられた可能性があります。

于 2014-07-04T06:24:32.950 に答える
5

正しいJon Skeetの答えを拡張するだけです。

これは、C# の await 式の Java 版ではありません。ホバー、一部の Java フレームワークには同じ機能があります。

実際、ルーチンやステートマシン コードをオンフライで生成します。

于 2013-07-07T16:05:29.220 に答える