2

次の例は、アクターに送信されるメッセージとして可変変数を使用できることを示しています。Scala Actorは、可変メッセージと不変メッセージを異なる方法で処理しますか?そうでない場合、なぜ人々は不変性がScalaが並行性に優れている理由であると言うのですか?

import scala.io._
import scala.actors._
import Actor._

def getPageSize(url : String) = Source.fromURL(url).mkString.length

var abc = "http://www.verycd.com"

def getPageSizeConcurrently() = {
  abc = "http://www.twitter.com"  // changing value

  val caller = self
  actor { caller ! (abc, getPageSize(abc)) }
  receive {
    case (url, size) =>
      println("Size for " + url + ": " + size)            
  }
}

getPageSizeConcurrently

更新:私はここでとても素敵な返事をもらいました。

4

3 に答える 3

3

他の人が指摘したように、あなたが質問を組み立てた方法は、それに答えるのを少し難しくしています。おそらくそれは、あなたがアクターに焦点を当てているためであり、あなたが作成した例は少し奇妙です.

要するに、Scala とその Actor 実装、および Actor の Akka 実装を使用すると、可変性で頭を撃ち抜くことができます。それがあなたが求めている中心的な質問のようです。それでよければ、ここで読むのをやめてください :)

ただし、不変性は並行プログラムの品質をさまざまな方法で向上させます。Scala の可変性と不変性を OO および関数型プログラミングと組み合わせることで、物事を実装する方法に多くの柔軟性がもたらされます。

人々が言わないように見えることは、プログラミングの概念には、ほとんどの命令型プログラマーが慣れているものとは異なるスタイルのプログラミングが不変に必要であるということです(私が学び始めたとき、私は確かにそれに慣れていませんでした)。多くの人は、これまでと同じ方法でコーディングし、可変オブジェクトを不変オブジェクトに置き換えて、利益を得ることができると考えているようです。そうではありません。

例を挙げると (一見どこにListでもある例ですが)、それを使用するコードをどのように書くかがわかります。

ListAkka の Future 実装を使用して、Int の s で本当にばかげたことを実行します。アルゴリズムはそれほど重要ではありません。重要なのは、そこにないもの、つまり同時実行保護を認識することです。完全に不変であるため、同時アクセスの問題について考える必要さえありません。何が起こっているのかを明確にするために、以下に型注釈を追加しました - Scala は実際にすべてを推測します。

import akka.dispatch.{ExecutionContext, Future, Await}
import akka.util.duration._
import java.util.concurrent.Executors

object Main {
  val execService = Executors.newCachedThreadPool()
  implicit val execContext = ExecutionContext.fromExecutorService(execService)

  def main(args: Array[String]) {
    // A Future list of 1's
    val flist: Future[List[Int]] = Future { (1 to 5) map { _: Int => 1 } toList }

    // The goal is to create a new list of Ints in 25 "iterations" across
    // multiple threads
    val result: Future[List[Int]] = (1 to 5).foldLeft(flist) { (acc, _) =>

      // "Loop" 5 times, creating 5 new lists of Ints, but these 'new' lists
      // share most of their content with the previous list
      val fs: IndexedSeq[Future[List[Int]]] = (1 to 5) map { i =>
        acc map { numlist =>
          (i * numlist.sum) :: numlist
        }
      }

      // Reduce the 5 lists we just created back down to one list again, by 
      // performing a pairwise sum across them all... in the Future
      Future.reduce(fs) { (a, l) =>
        (a zip l) map { case (i, j) => i + j }
      }
    }

    // Wait for the concurrency to complete and print out the final list
    println(Await.result(result, 1 second))

    // Shut down the execution system that was running our stuff concurrently
    execContext.shutdown()
  }
}
// Prints: List(12000000, 3000000, 750000, 187500, 46875, 3125, 3125, 3125, 3125, 3125)

(i * numlist.sum) :: numlistからのすべての使用ビットで作成される中間リストnumlist。そのループから出てくる 5 つの新しいリストは、実際にはnumlist、5 つのまったく新しいリストではなく、へのポインタを持つ 5 つの新しい値として作成されます。つまりlist1 = "newvalue" + oldlistlist2 = "another new value" + oldlistなど...

プログラミングは、変換のモデルを不変に意味します。データ構造を取得し、それを何かに渡し、それを変換して他の人に渡します。変更可能なプログラミングのがはるかに高速で信頼性が高く、実行内容によっては遅くなる可能性もありますが、@mhs が述べたように、結論としては、安全性の観点から推論する方が簡単です。

これが命令型プログラミングの通常のモードにどのようにマップされるかは明らかではありません。一般にそうではないからです。また、それがすぐに意味をなさない理由でもあります。コーディングは他のことと同じで、新しいパラダイムを真に理解するには時間がかかります。

于 2012-07-14T16:17:49.230 に答える
2

あなたの質問は少し奇妙だと思います。おそらく、不変の方が並行性に優れているのに、なぜ Scala にはまだ可変変数 / データ構造があるのか​​疑問に思っているのでしょうか?

はい、不変性は並行性に優れており、他の人が答えたように、コードについて簡単に推論できます。

しかし、それはミュータブルが役に立たない、または本質的に悪いという意味ではありません。ミュータブルvarまたはデータ構造を使用した実装の方が簡単な場合や、特定のケースではより高速に実行される場合があります。

Scalaは、Haskell のようにすべての不変を強制するのではなく、不変のデータ構造を提供し、使用することを推奨します。val

ただし、変更可能なものも提供します。本当に必要な場合は、そこにあることを確認してください。

あ、はい。Scala/Akka アクターは変更可能なメッセージを不変のものと同じように処理しますが、正当な理由がない場合はそうすべきではありません。

を使用している場合varは、正当な理由も必要であり、スコープを制限する必要があります。

于 2012-07-15T00:16:53.567 に答える
1

不変性は、並行プログラムの正確性に関する推論を容易にします。アクター間で共有するすべてのオブジェクトが不変であると仮定すると、他のアクター (サードパーティによって実装される可能性がある) が実際に何をするかを知らなくても、それらに関する仮定を安全に保つことができます。たとえば、fすべてのフィールドに正の値が含まれる 10 個のオブジェクトを含む不変リストをインスタンス化したことがわかっている場合、そのリストを他のユーザーと共有している場合でも、この仮定を使用して安全に作業を続行できます。リストに正のフィールドを持つ要素がまだ 10 個あるという前提にコードが依存している状況ですが、f実際には、別の攻撃者が負のfフィールドを持つ要素を 1 つだけ含むようにリストを変更した場合です。

不変性は、一般的に、つまり逐次的な場合でも、プログラムに関する推論をはるかに容易にします。これが、Java や C# の正確性を証明するよりも Haskell プログラムの正確性を証明する方がはるかに簡単である理由の 1 つです。後者の場合、分離ロジック暗黙的な動的フレームなどの特殊なロジックが必要です。これにより、共有された変更可能な状態について推論できます。興味がある場合は、VeriFast (SL 用) と Chalice (プロジェクト ページWeb インターフェイス) をご覧ください。、IDF 用) であり、どちらも変更可能なデータ構造とエイリアシングを含むプログラムの実験的な検証ツールです。ただし、これは進行中の研究分野であることに注意してください。通常、これらの検証者は実際のプログラムを処理できません。

要するに、データが不変であることがわかっている場合、他の誰にデータを渡しても問題はなく、データを変更したり、作業の前提を破ったりすることはできません。

于 2012-07-14T09:31:58.300 に答える