2009-10-10 5 views
48

Я чувствую себя немного небезопасно в отношении использования актеров в Скале. Я прочитал документацию о том, как делать вещи, но, я думаю, мне также нужны некоторые правила НЕ, чтобы они могли свободно их использовать. Я думаю, я боюсь, что буду использовать их неправильно, и я даже не заметлю этого.Актеры Scala - худшие практики?

Можете ли вы придумать что-нибудь, что, если оно будет применено, приведет к нарушению преимуществ, которые приносят актеры Скала, или даже ошибочные результаты?

ответ

52
  • Избегайте !? везде, где это возможно. Вы будет получить запертую систему!

  • Всегда отправляйте сообщение из потока подсистемы Actor. Если это означает, что создание переходного актера с помощью метода Actor.actor то пусть так и будет:

    case ButtonClicked(src) => Actor.actor { controller ! SaveTrade(trdFld.text) }

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

    case other => log.warning(this + " has received unexpected message " + other

  • Не используйте Actor.actor для ваших основных актеров, sublcass Actor вместо этого. Причина этого заключается в том, что только путем подкласса вы можете обеспечить разумный метод toString. Опять же, отладки актеров очень трудно, если ваши журналы завалены заявлениями типа:

    12:03 [INFO] Sending RequestTrades(2009-10-12) to scala.actors.Actor$anonfun$1

  • документов актеры в вашей системе, прямо указав, какие сообщения они будут получать и как именно они должны вычислить ответ. Использование актеров приводит к преобразованию стандартной процедуры (обычно инкапсулированной в рамках метода), чтобы стать логическим разбросом по реакциям нескольких актеров. Легко потеряться без хорошей документации.

  • Всегда проверяйте связь с вашим игроком вне его петли react, чтобы найти ее состояние.Например, я всегда объявляю метод, который вызывается с помощью MBean, который выглядит следующим образом. В противном случае может быть очень сложно определить, работает ли ваш актер, выключен, имеет большую очередь сообщений и т. Д.

.

def reportState = { 
    val _this = this 
    synchronized { 
    val msg = "%s Received request to report state with %d items in mailbox".format(
        _this, mailboxSize) 
    log.info(msg) 
    } 
    Actor.actor { _this ! ReportState } 
} 
  • Link ваши актеры вместе и использовать trapExit = true - в противном случае они могут не беззвучно означая ваша программа не делает то, что вы думаете, и, вероятно, выйти из памяти, сообщения остаются в почтовом ящике актера.

  • Я думаю, что некоторые другие интересные варианты вокруг дизайн-решений, которые будут сделаны с помощью актеров были выделены here и here

+0

Все ваши другие моменты имеют смысл сразу, но мне любопытно, что вы второй раз отправляете сообщения из потока Actor. Какова основная мотивация здесь, производительность/ясность/что-то еще? Я не совсем понимаю. – Michael

+0

Я вижу, что вы сильно написали код актера в Scala! :-) –

+2

* @ Michael * - если вы явно не объявите Актера самостоятельно, он будет создан для вас и привязан к 'Thread' как' ThreadLocal'. Мне совершенно не ясно, что этот подход либо логически безопасен, либо свободен от утечек памяти. Намного проще явно объявить один –

12

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

Я полагаю, вы уже видели принципы актера в Программирование на Scala, но и для записи:

  • Актеры не должны блокировать во время обработки сообщения. Там, где вы захотите блокировать, попробуйте организовать вместо этого сообщение.
  • Используйте react {}, а не receive {} если возможно.
  • Общайтесь с актерами только через сообщения.
  • Предпочитают непреложные сообщения.
  • Сделать сообщения самодостаточными.
+0

Здравствуйте, Спасибо за ваш быстрый ответ - это делает действительно полезные пункты. Я думал, что «совместное состояние» - это что-то, чего нельзя сделать ... но я точно не знаю, что это означает на уровне кода - возможно, - имея в качестве сообщения класс C с частным полем F и с классический геттер для этого поля (getF) - от одного актора, отправив экземпляр C - для актера-актера, принимающего C и вызывающего getF ? Может ли это означать «совместное состояние»? Спасибо! – teo

+0

Общее состояние доступно для доступа несколькими потоками. Это не так плохо, как разделяемое изменчивое состояние, но оно требует рассуждения о согласованности, если оно не разделяется только после построения и впредь неизменного. Таким образом, отправка ссылки на себя в сообщении не будет самым умным движением, хотя ссылка на изменяемый объект хуже ссылки на неизменяемую. – DigitalRoss