gal*_*ize 5 concurrency multithreading functional-programming
我遇到过这样的说法:
"以函数式编程使得状态显示给你的代码,这使得更容易推理,并且在完全纯粹的系统中,使线程竞争条件变得不可能."
我看到了这个观点,但我怎样才能在现实世界中解决这个问题呢?
例如:
有一个功能程序有两个功能:
def getMoney(actMoney: Integer, moneyToGet: Integer): Integer
= actMoney - moneyToGet
def putMoney(actMoney: Integer, moneyToPut: Integer): Integer
= actMoney + moneyToPut
Run Code Online (Sandbox Code Playgroud)
然后,我真的想为给定的帐户定义函数getActualMoney和saveActualMoney,但我不能,它们不是纯粹的.那是因为我从一些内存中获取给定帐户的Money,并且将给定帐户的Money存入某些内存(存在状态).
def getActualMoney(accountNo: String): Integer = {...}
def saveActualMoney(accountNo: String, actMoney: Integer): Unit = {...}
Run Code Online (Sandbox Code Playgroud)
因此,我必须从"外部"获取当前的资金.让我们说,我的程序正在以这种方式工作.现在我有两个同时请求,第一个:获得一些钱,第二个为同一个帐户存入一些钱.当然,我会得到两个不同的结果.所以有竞争条件.
我明白,我应该在这个帐户"外部"编程代码上进行交易.所以,这种情况不应该发生.为了更好的并发性,函数应如下所示:
def getMoney(
acountNo: String,
actMoney: Integer,
moneyToGet: Integer): (String, Integer)
= (acountNo, actMoney - moneyToGet)
def putMoney(
acountNo: String,
actMoney: Integer,
moneyToPut: Integer): (String, Integer)
= (acountNo, actMoney + moneyToPut)
Run Code Online (Sandbox Code Playgroud)
这是怎么回事?值得做吗?
Chr*_*ong 13
虽然引用在技术上是正确的,因为你不能在纯函数代码中有竞争条件,你确实需要有副作用,以便程序除了计算一个值之外做任何有用的事情,所以它有点不诚实,尽管同时它确实说出了有用的区别.
以最小化副作用并最大化纯函数代码的样式进行编程将减少代码区域,其中竞争条件可能发生在您知道明确使用副作用的那些地方,这通常是纯功能编程所吹捧的好处倡导者.
例如:如果有钱的帐户只是模拟只存在于您的程序中,那么通过让帐户上的每个操作都返回一个具有更新值的新帐户对象,可以很容易地将它们保留为纯函数.如果你这样做,你将获得纯函数代码的好处:能够通过使用"等式推理"来推理引用透明代码,这是你可以假设对函数的任何调用等同于值该函数返回给定它传递的参数,无论您按什么顺序调用它的次数.(这是为了回答你的问题"它值得做吗?")
但是,如果你在谈论一个系统,比如在外部数据库中存储账户和余额,那么你肯定需要副作用,你必须关注操作的顺序和潜在的竞争条件,就像你在任何其他语言.通过隔离您的副作用,不过,你可以更加肯定,你就必须关心这些并发问题,也使使用更高级别的并发性的抽象,如MVars,IORefs,或STM(可在Haskell和,似乎,Scala),鼓励在不纯净的数据上使用纯操作 - 保持隔离和可组合的东西.