直感的な同時プログラミング抽象化を備えた最新のプログラミング言語[非公開]


40

私は、システムプログラミングではなく、アプリケーション/ユーザーレベルに重点を置いて、並行プログラミングを学ぶことに興味があります。並行アプリケーションを記述するための直感的な抽象化を提供する最新の高レベルプログラミング言語を探しています。生産性を高め、並行プログラミングの複雑さを隠す言語に焦点を当てたいと思います。

私の生産性が低下し、プログラミングモデルが直感的ではないため、いくつかの例を挙げると、C、C ++、またはJavaでマルチスレッドコードを記述する良いオプションは考えられません。一方、生産性を高め、Pythonやマルチプロセッシングモジュール、Erlang、Clojure、Scalaなどのより直感的な抽象化を提供する言語は、適切なオプションです。

あなたの経験とその理由に基づいて何をお勧めしますか?

編集:あなたの興味深い答えをみんなに感謝します。Erlang、Clojure、Scala、Groovy、そしておそらくHaskellなど、多くの優れた候補者がいるため、実際に試さずに結論を出すことは困難です。私は最も説得力のある議論で答えを投票しましたが、どれを選ぶか決める前にすべての良い候補者を試します:)


21
To give an example, I don't consider a good option writing multithreaded code in C, C++, or Java。どうして?On the other hand, Python and the multiprocessing module, Erlang, Clojure, Scala, etc. are some of my options.繰り返しますが、なぜですか?質問を展開して、実際に探しているものをより明確にします。
ヤンニス

2
だから、すべての落とし穴を使って並列プログラミングを学びたいですか、それとも複雑さを隠して生産性に集中したいですか?
MAR

@MaR生産性に焦点を当て、複雑さを隠します:)
sakisk

これらの言語のいくつかでは、多くの重要な概念が回避されている(一部は解決済みと言われることもある)ため、Cは並行性を学ぶのに最適な言語です。(または、少なくとも私にはそう思われます。リストされているすべての言語について十分に知りません)。多くの場合、生産性の向上は包括的な学習と相反します。
user606723

1
@DeadMG生産性の低下が彼らの問題です。問題の代わりに言語の構文に集中したくありません。私は間違いなく、行き詰まりに苦しむことを望まない。単純な例として、次のような単純なステートメントを使用したいと思いbegin transaction end transactionます。また、内部のすべてはデッドロックがなく、全体として成功または失敗する必要があります。
サキスク

回答:


33

Clojureはほぼ間違いなく見るべきです-私の意見では、これはマルチコアプログラミングに最適な最新の言語であり、非常に生産的です。

主な属性:

  • これは関数型言語です。これは、並行性と、より高いレベルの抽象化を使用して開発する能力の両方に恩恵をもたらします。Haskellのような関数型言語の経験がある人なら誰でも知っている、完全に不変の永続データ構造と遅延シーケンスを備えています。
  • 可変状態への同時ロックフリーアクセスのための非常に斬新なソフトウェアトランザクションメモリシステムを備えています。コードの並行性を安全にすることは、多くの場合、(dosync ....)ブロックにラップするのと同じくらい簡単です。
  • それはだLispのマクロベースのメタプログラミングとコード生成のために、それは非常に強力になり- 。これにより、生産性が大幅に向上します(Paul Grahamのエッセイ-「平均を破る」)
  • これはJVM言語です。したがって、Javaエコシステムの膨大なライブラリとツールにアクセスできるだけでなく、JVMを同時サーバー側アプリケーションの効果的なプラットフォームにするために費やされた膨大なエンジニアリング努力の恩恵も受けます。実用的な目的のために、これは、この種の基盤を基礎としない言語よりも大きな利点をもたらします。
  • それのダイナミックな -非常に簡潔なコードになり、生産性がたくさん。ただし、必要に応じて、パフォーマンスのためにオプションの静的型ヒントを使用できることに注意してください。
  • この言語は抽象化中心に設計されており、説明がやや困難ですが、最終的な効果は、問題を解決するために組み合わせることができる比較的直交する機能のセットを取得することです。例としては、シーケンスの抽象化があります。これにより、すべての「シーケンシャル」タイプのオブジェクト(リスト、文字列、Java配列、無限遅延シーケンス、ファイルから読み取られる行などを含む)を処理するコードを記述できます。
  • あります偉大なコミュニティ役立つ、洞察力の最も重要な非常に実用的では- - Clojureの中焦点は「物事を成し遂げる」で、一般的です。

並行性の傾斜があるいくつかのミニコードサンプル:

;; define and launch a future to execute do-something in another thread
(def a (future (do-something)))

;; wait for the future to finish and print its return value
(println @a)

;; call two functions protected in a single STM transaction
(dosync
  (function-one)
  (function-two))

特に、次のビデオを1つ以上見る価値があります。


21
強く型付けされた言語での静的型宣言の目的は「必要に応じてパフォーマンスを改善する」ことではなく、その古いストローマンを駆け抜けるLisp支持者にうんざりしています。型宣言には2つの目的があります。特定のコンパイル時の正確性の保証と、特に元の作者以外の人のためにコードを読みやすくすることです。静的型付けが提供する本質的に優れたパフォーマンスは単なるボーナスです。
メイソンウィーラー

8
最近仕事で別の開発者のJavaScriptコードを使用する必要がありましたが、それがプロセスの最も苦痛な部分です。関数の引数に型がないため、コードベース全体を探して何を想定するのかを把握する必要があります彼らがどこから呼ばれたかに基づいて彼らができること JavaScriptが一般的な構文に加えてCの型システムを保持していた場合、これは問題になりません。
メイソンウィーラー

1
@MasonWheeler:型注釈なしで関数を呼び出す方法がわからない場合は、ドキュメントの問題(またはその欠如)です。アヒル型言語であっても、通常はすべてが何らかの構造型の制約を満たす必要があります(たとえば、算術演算をサポートする必要がある、反復可能である必要がある、インデックス可能である必要があるなど)。静的型は、関数何をするのかについて多くのヒントを与えないため、最小限にしか役立ちません。
dsimcha

2
@Mason静的型宣言に他の利点はないと言ったことはありません。実際、私はあなたが述べた正確な理由から静的型宣言が好きです。しかし、動的型付けの生産性向上も気に入っています。それはトレードオフです。優れたテストスイートがある場合、一般的に、これにより、正確性の確保と、初心者が正しい使用法を理解できるようにサンプルコードを提供するという点で、動的型付けの多くの欠点が軽減されることがわかります。YMMV。
ミケラ

1
@dsimcha-抽象化を中心に設計する代わりに、具体的な実装を中心に設計することもできます。たとえば、古いLisp関数のほとんどは、コンスセルに保存されているリンクリストでのみ機能していました。データ構造ごとに異なる機能が必要でした。Clojureでは、コアライブラリ関数はシーケンシャルなもの(答えのように)で動作します。
ミケラ

27

Dを試すことができます。3つのモデルがあります。最初または2番目のいずれかをお勧めします。

  1. std.concurrency。このモジュールをすべての同時実行のニーズに使用する場合、言語と標準ライブラリの組み合わせにより、スレッド間の分離が強制されます。スレッドは、主にメッセージの受け渡しを介して通信しますが、共有メモリのサポートは限定的であり、「安全第一」を優先し、低レベルのデータ競合を許可しません。残念ながらstd.concurrencyのドキュメントは改善が必要ですが、モデルはAndrei Alexandrescuの本「The D Programming Language」の無料の章に記載されています。

  2. std.parallelism。このモジュールは、一般的な同時実行性ではなく、マルチコア並列処理用に特別に設計されています。(並行性と並列性は同じものではありませんが、並行性の実装には並行性が必要です。)並列性のポイントはすべてパフォーマンスであるため、std.parallelismは効率的な並列コードの作成を困難にするため、分離保証を行いません。ただし、エラーが発生しやすい低レベルの詳細の多くは抽象化されるため、手動で検証したワークロードを相互に独立させて並列化する場合は、非常に困難です。

  3. core.threadは、OS固有のスレッドAPIの低レベルラッパーです。std.concurrencyとstd.parallelismはどちらも内部で使用しますが、独自の同時実行ライブラリを作成している場合、またはstd.parallelismまたはstdのどちらでもうまく行えないばかげたコーナーケースを見つけた場合にのみ使用することをお勧めします.concurrency。日常業務にこの低レベルのものを使用しないでください。


不変性/純度、デフォルトでスレッドローカルストレージ、および順番に変異を課す共有について言及しているはずです。これらは、C / C ++で欠落している言語サポートであり、一致するコードを記述します。
deadalnix

@deadalnix:私にとって、それらのほとんどはstd.concurrencyモデルの詳細です(分離がどのように実施されるか)。この投稿を簡潔にしたかった。
dsimcha

まあ、実際はありません。同時実行には、ライブラリと言語サポートの両方が必要です。
deadalnix

@deadalnix:その通りですが、主にstd.concurrencyをサポートするために配置されました。
dsimcha

23

Erlangは間違いなく素晴らしい選択肢ですが、もう少し実用的なのは、Googleの新しい言語であるGoです。

他の一般的な言語からそれほど遠くないので、他の「簡単な」言語を既に知っている場合、通常は簡単に入手できます。多くの人は、それをPythonやLuaと比較して、プログラムするのがどの程度快適かという点で比較しています。


@faifは、システムの並行プログラミングではなく、アプリケーション/ユーザーレベルについて質問しています。Erlangはこれにどのように適合しますか?
カイロン

@Raynos:コミュニティに依存します。
ドナルドフェローズ

@DonalFellowsあなたの権利、私は私の文が狭すぎたと思う
レイノス

1
@Chiron:Erlangはプログラミング言語であり、アプリケーションの作成に使用されます。通常、マルチプロセッシングアプリケーション。「システムコンカレントプログラミング」としてどこに収まるのかわかりません。Erlangで書かれたOSは聞いたことがありません。
ハビエル

1
Goチュートリアルを簡単に確認した後、(制限された)ポインターを使用するCのような構文を持つ言語のIMHOは、間違いなく生産性を向上させる最新の言語ではないと言いたいです。
サキスク

23

見てみましょう.NETは、Microsoftの並列プログラミングを。非常に直感的です。

多くのパーソナルコンピューターとワークステーションには、複数のスレッドを同時に実行できる2つまたは4つのコア(CPU)があります。近い将来のコンピューターは、かなり多くのコアを持つと予想されます。現在および将来のハードウェアを活用するには、コードを並列化して、複数のプロセッサに作業を分散できます。過去には、並列化にはスレッドとロックの低レベルの操作が必要でした。Visual Studio 2010および.NET Framework 4は、新しいランタイム、新しいクラスライブラリタイプ、および新しい診断ツールを提供することにより、並列プログラミングのサポートを強化します。これらの機能により、並列開発が簡素化されるため、スレッドやスレッドプールを直接操作することなく、効率的できめ細かい、スケーラブルな並列コードを自然なイディオムで記述できます。 http://i.msdn.microsoft.com/dynimg/IC292903.png


+1これはまさに彼が求めているものです。ただし、問題が発生した場合、下位レベルでの同時実行性を理解しないと、問題をデバッグすることは困難です。言うまでもなく、これをC#の初心者として採用することは...興味深いことです。
P.Brian.Mackey

@ P.Brian.Mackey-同意します。しかし... 1が完全にリレーショナルモデルとSQLを理解していないときのORMを使用して、これを比較するためのストレッチではないでしょう、珍しいことではありませんこと
のOtavioDécio

1
特にPLINQ。タスクのごく一部のサブセットに対してのみ有用ですが、非常に使いやすい場合があります。
svick

21

ErlangとScalaの両方に、アクターベースの同時実行性があり、非常に直感的で習得しやすいことがわかりました。

コンピューターサイエンスのアクターモデルは、「アクター」を同時デジタル計算の普遍的なプリミティブとして扱う同時計算の数学モデルです。受信したメッセージに応じて、アクターはローカル決定を行い、より多くのアクターを作成し、より多くのメッセージを送信できます、受信した次のメッセージへの応答方法を決定します...これは、計算の理論的理解のフレームワークとして、および並行システムのいくつかの実用的な実装の理論的基盤として使用されています。


19

私は今Haskellについて学んでいますが、この論文を読んでHaskellは並行プログラミングの良い選択肢であると確信しました。それは純粋に機能的であるため(型システムは、関数が入力、出力、またはグローバル状態の読み取り/変更を行うかどうかを知っています)、トランザクションと同様に動作するソフトウェアトランザクションメモリ(上記の論文で非常にうまくまとめられています)のようなことができますデータベースで-わずかな余分な砂糖だけで原子性のような素晴らしいものがたくさん得られます。私の知る限り、Haskellスレッドは非常に軽量です。これらに加えて、Haskellが純粋に機能的であるという事実により、単純なタスクでさえも、たった1つのキーワード(par)で並行して実行できます。ソース


7

GoogleのGO言語には、並行処理のための興味深いツールがいくつかあります。http://golang.org/doc/effective_go.html#concurrencyを参照し、例を参照してください

コンカレントプログラミングは大きなトピックであり、ここではGo固有のハイライトの一部のみを紹介します。

多くの環境での同時プログラミングは、シェア変数への正しいアクセスを実装するために必要な微妙さにより困難になります。Goは、チャネル上で共有された値が渡され、実際には、別々の実行スレッドによってアクティブに共有されることのない、異なるアプローチを推奨します。一度に1つのゴルーチンのみが値にアクセスできます。設計上、データの競合は発生しません。この考え方を奨励するために、スローガンに減らしました。

メモリを共有して通信しないでください。代わりに、通信してメモリを共有します。

このアプローチは、あまりにも遠すぎます。参照カウントは、たとえば、整数変数の周りにミューテックスを配置することで最適に実行できます。しかし、高レベルのアプローチとして、チャネルを使用してアクセスを制御すると、明確で正しいプログラムを簡単に作成できます。

このモデルについて考える1つの方法は、1つのCPUで実行される典型的なシングルスレッドプログラムを検討することです。同期プリミティブは必要ありません。次に、このような別のインスタンスを実行します。同期も不要です。次に、これら2つの通信を許可します。通信がシンクロナイザーである場合、他の同期の必要はありません。たとえば、Unixパイプラインはこのモデルに完全に適合します。Goの並行性へのアプローチはHoareのCommunicating Sequential Processes(CSP)に由来していますが、Unixパイプのタイプセーフな一般化として見ることもできます...


6

次のバージョンでは、C#により、図に示されているよりもさらに簡単になります。2つの新しいキーワードAsyncとAwaitがあります。

非同期は関数修飾子として使用され、「この操作は別のスレッドで処理を実行します。

AwaitはAsync関数内で使用され、ここで魔法が発生します。基本的にAwaitは、別のスレッドでキーワードに続く操作を実行し、結果を待つようにコンパイラーに指示します。await呼び出し後のコードは、操作後に実行されます。

また、操作は呼び出しスレッドと同期します(したがって、ボタンのクリックに応答して非同期操作を実行している場合、UIスレッドに手動でポストバックする必要はありません)。2つの小さなキーワードを使用すると、多くの同時実行性が得られます。詳細はこちら


適切なOS C#コンパイラは、すでにC#5、async、awaitをサポートしています。
Raynos

基本的にAwaitは、別のスレッドでキーワードに続く操作を実行し、結果を待つようにコンパイラーに指示します。この答えは正しいのだろうか-非同期待機はスレッドに関するものではありません。この記事は素晴らしいと説明しています
-sventevit

いい視点ね。私はそれについてあまりにも単純に話していたと思います。実際に行われるのは、「待機」中のタスクのイベントをサブスクライブする「継続」が行われることです。そして、はい、特定のI / O操作とthread.sleep()(基本的にクロック割り込みに応答します)にはスレッドがありません。しかし、I / Oのような手動で作成されたタスクについては、待ちに待ったフィボナッチ電卓を作成したと言えますか?技術的には「スレッドはありません」という記事は正しいのですが、実際にはありませんでした。これは常に、OSが行っていることの詳細を隠すために使用する概念でした。
マイケルブラウン

6

私はまだC ++をお勧めします。まともな並行コードを書くために必要な抽象化が可能である以上です。圧倒的な可能性は、ジョブを実行するための優れたライブラリは比較的新しく、実際、C ++を使用するための知識は必ずしも一般的ではないためです。IntelのTBBは数年前から存在し、MicrosoftのPPLは昨年以来出荷されています。

あなたはTBBまたはPPLのようなものを使用する場合は、並行コードは、よく、正確にされていない些細な書き込みに、その同時実行限り些細なことはありませんが、はるかに困難から。pthreadまたはWin32スレッドを直接使用する場合、それが気に入らないのも不思議ではありません。このような関数を使用して実際にアセンブラーで記述しています。しかし、PPLでは、並列化された標準機能アルゴリズム、同時アクセス用の汎用データ構造、およびそのような優れた機能について説明しています。


1
Boost.ThreadsまたはC ++ 0x std::thread(またはstd::tr1::thread)を確認してください。実際には、非常に優れた抽象化、IMOです。
greyfade

1
@greyfade:PPLやTBBにはまったく何もありません。boost::threadは、小さなRAIIを備えたOSラッパーです。PPLとTBBは、など実際の並列アルゴリズム、コンテナー、ある
DeadMG

6

Adaのプラグインは、並列処理と並行処理のためのすべてのトップレベルの抽象化を備えているため、ここで必要です。それ以外の場合はタスクとして知られています。また、OPが直感的な(主観的な基準!)


5

アクター、データフロー、通信シーケンシャルプロセス(CSP)、データ並列処理、ソフトウェアトランザクションメモリ(STM)、エージェントなどを可能にするため、JVMベースにできる場合は、Groovy / Java / GParsをお勧めします。ここでのポイントはそれぞれが異なる「スイートスポット」を持つ、多くの高レベルの並行性および並列性モデルです。構築しようとしている問題の解決策と調和しないモデルを使用することは望ましくありません。モデルが1つだけの言語とフレームワークでは、アルゴリズムハッキングを強制されます。

もちろん、GroovyとGParsに貢献しているので、私は偏見を抱いているように見えるかもしれません。一方、私はCSPとPythonを使用しています。Python-CSP。

さらに重要な点は、元の質問は学習に関するものであり、本番システムの作成に関するものではないということです。したがって、Groovy / Java / GParsの組み合わせは、最終的な生産作業がJVMベースではなく、Just :: Thread ProやTBBのようなものを使用してC ++で行われた場合でも、学習の良い方法です。

(ホストサイトによるスパムのパニックが原因で、完全に合理的なURLリンクを削除する必要がありました。)


ラッセル、必要に応じて、チャットルームでリンクするものを教えてください。チャット用に追加します。chat.stackexchange.com
Dan McGrath

4

Clojureはどうですか?たとえばSwingを使用できますが、Clojureの並行プログラミング機能を楽しんでいますか?Clojureは、Javaと非常によく統合されています。

また、Java 7 Fork / Joinフレームワークを検討しましたか?



0

Scalaは質問と回答で何度も言及されていますが、ScalaとJavaの両方で使用できるアクター実装であるAkkaについては言及していません。


この答えの何が問題になっていますか?他の答えはakkaに言及しておらず、akkaは並行プログラミングのための高レベルの抽象化を実装しています。
ジョルジオ

-1

それはあなたが構築しているものに依存すると思います。デスクトップアプリ、またはサーバー?(個人的な経験はありませんが)node.jsは、サーバーの同時プログラミングに最適です(コードの作成とパフォーマンスの両方の面で)。新しいサーバーアプリを作成する場合は、おそらくそれを試してみます。デスクトップアプリについてはわかりません...私はC#でかなりの量を書きましたが、複雑さをうまく隠すツールがいくつかあります。


-1

私はこれで頭にぶつかるかもしれませんが、TAOUPの第7章を読んでいますか?私が特に考えているセクションは、スレッド対プロセスです。同時処理の概念により、ほとんどの人がスレッドを考えるようになりましたが、スレッドが子プロセスを生成するよりも簡単で高速に使用できるインスタンスを見たことはありません。

あなたはあなたのOSを構築した賢い人たちに並行処理の詳細をすべて伝えています。すでに多くの通信方法が用意されており、共有リソースのロックについて心配する必要はありません。基本的に、スレッドは効率化のハックであり、最適化のルールに該当します。必要性をテストしていない場合は最適化しないでください。

pythonのenvoyなど、適切なサブプロセスライブラリを見つけます。あるいは、Cでいくつかの別個のプログラムを作成し、フォークとパイプを使用してサブプロセスを生成および通信する別の「マスター」プログラムを作成することもできます。


3
これは、OPが明示的に望んでいることの反対です。プロセスの生成は、スレッドを手動で生成するのと同じくらい低レベルです。OPは、並行性の高レベルの抽象化に関心があります。
コンラッドルドルフ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.