2015-05-06 2 views
4

я столкнулся с таким утверждением:условия гонки в чистом функциональном программировании

«Программирование в функциональном стиле делает государство представлено в код явного, что делает его гораздо легче рассуждать о, и, в совершенно чистой система, делает условия гонки нитей невозможными ».

Я вижу эту точку зрения, но как я могу достичь этого в реальных проблемах?

Например:

Существует функциональная программа с двумя функциями:

def getMoney(actMoney: Integer, moneyToGet: Integer): Integer 
    = actMoney - moneyToGet 

def putMoney(actMoney: Integer, moneyToPut: Integer): Integer 
    = actMoney + moneyToPut 

Тогда, я действительно хотел бы определить функции getActualMoney и saveActualMoney для данного счета, но я не могу, они не чисты. Это потому, что я получаю деньги за данную учетную запись из некоторой памяти, и я сэкономлю деньги для данной учетной записи в какой-то памяти (есть состояние).

def getActualMoney(accountNo: String): Integer = {...} 

def saveActualMoney(accountNo: String, actMoney: Integer): Unit = {...} 

Поэтому я должен получить свои текущие деньги из «снаружи». И, допустим, моя программа работает таким образом. Теперь у меня есть два одновременных запроса: во-первых: получить немного денег, а второй - за ту же учетную запись. Конечно, я получу два разных результата. Так что есть состояние гонки.

Понимаю, что я должен совершить транзакцию на этом «внешнем» программном коде. Так что такой ситуации не должно было быть. Для лучшего параллелизма функции должны выглядеть так:

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)   

Это то, что происходит? Стоит ли это делать?

ответ

10

Хотя цитата технически правильная, поскольку вы не можете иметь условия гонки в чисто функциональном коде, вам действительно нужно иметь побочные эффекты, чтобы программа могла делать что-нибудь полезное, кроме вычисления значения, и поэтому несколько неискренне, хотя в то же время он говорит о полезном различии.

Программирования в стиле, который сводит к минимуму побочных эффектов и максимизирует чисто функциональный код уменьшит область кода, где условие гонки может произойти в те места, где вы знаете, вы явно с помощью побочных эффектов, и это является часто выгоды, рекламируемые чисто функциональными программистами.

Для вашего примера: если учетные записи с деньгами - это просто симуляции, которые живут только в вашей программе, было бы легко сохранить их как чистые функции, поскольку каждая операция в учетной записи возвращает новый объект учетной записи с обновленные значения. Если вы это сделаете, вы получите преимущества чисто функционального кода в целом: возможность рассуждать о ссылочно прозрачном коде с помощью «эквационального рассуждения», где вы можете предположить, что любой вызов функции эквивалентен значению что функция возвращает данные, переданные им, независимо от того, сколько раз вы вызываете ее в каком порядке. (чтобы ответить на ваш вопрос «стоит ли это делать?»)

Но если вы говорите о системе, которая, скажем, хранит учетные записи и балансы во внешней базе данных, тогда вам обязательно нужны побочные эффекты, и вы должны быть обеспокоены порядком операций и потенциальными условиями гонки так же, как и на любом другом языке.Однако, изолируя ваши побочные эффекты, вы можете быть более уверенными в том, где вы находитесь do должны заботиться о таких проблемах параллелизма, а также использовать абстракции параллелизма более высокого уровня, такие как MVars, IORefs или STM (доступны в Haskell и, по-видимому, Scala), которые поощряют использование чистых операций на нечистых данных, сохраняя вещи изолированными и составными.

Смежные вопросы