1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
# ActorSystem
## Sending
Обычная отправка (Send) сообщения проходит следующим образом:
1) По получателю находится MailBox
2) Кладется сообщение в мейлбокс
3) Проверяется единсвенное ли это сообщение в мейлбоксе, если нет, то больше ничего не делаем
4) Иначе кладем сообщение в очередь активаций и в случае наличия спящих потоков, будим один из них
Из этого следует, что мы всегда стараемся будить поток.
Например если 2 актора пересылают друг другу сообщение, то они будут по переменно работать в разных потоках.
Но они вполне могли бы работать на одном потоке, и скорее всего это бы работало эффективней:
* Кеши не теряются из перехода с одного потока на другой.
* Меньше затрат на пробуждение потоков.
Для этого сделали два других способа отправки Send<ESendingType::Lazy> и Send<ESendingType::Tail>
Send<ESendingType::Lazy> старается придержать мейлбокс в который отправили сообщение, до окончания обработки текущего мейлбокса и работае следующим образом:
1) По получателю находится MailBox
2) Кладется сообщение в мейлбокс
3) Проверяется единсвенное ли это сообщение в мейлбоксе, если нет, то больше ничего не делаем
4) Захватываем мейлбокс
5) Если до этого уже захватили мейлбокс, то старый кладется в очередь активаций и пробуем разбудить спящий поток
6) После завершения обработки текущего мейлбокса проверяется, есть ли активация в очереди активаций. Если есть, то берем из очереди активаций мейлбокс, а захваченный кладем в очередь активаций, если же очередь активаций была пустая, то обрабатываем захваченный мейлбокс
Из плюсов, может лишний раз не будить поток и обрабатывать сообщения в том же потоке.
Из минусов, если после использования Send<ESendingType::Lazy> текущий мейлбокс будет долго обрабатываться, то это время добавиться к времени ожидания отправленного сообщения. Так как его мейлбокс захвачен потоком и не обрабатывается. Так же при сильной загрузки системы, когда очередь активаций всегда большая, отправленным сообщения будет добавляться летенси, так как мы не сразу отправляем сообщение, а ждем пока обработка мейлбокса закончится. И так как очередь акттиваций всегда не пустая, то мы с задержкой кладем мейлбокс в очередь активаций, хотя могли сделать это сразу.
Стоит использоваться желательно перед смертью актора, когда известно что больше он ничего обрабатывать не будет.
Для случаев, когда мы не хотим ждать окончания обработки мейлбокса или смерти актора, и хотим гарантировано обработать отправленное сообщение в том же потоке, следует использовать Send<ESendingType::Tail>.
После обработки текущего сообщение, обработка мейлбокса прервется, и начнется обработка захваченного мейлбокса. При этом передается квота с которым обрабатывался первый мейлбокс. Благодаря этому не получится заблокировать поток двумя акторами пересылающими друг другу сообщения. В какой-то момент кончится квота по времени или по количеству обработанных сообщений.
Send<ESendingType::Tail> работает следующим образом:
1) По получателю находится MailBox
2) Кладется сообщение в мейлбокс
3) Проверяется единсвенное ли это сообщение в мейлбоксе, если нет, то больше ничего не делаем
4) Захватываем мейлбоксa
5) Все остальные отправки сообщений будут работать как обычный Send
6) После завершения обработки текущего сообщения, прерывается обработка мейлбокса и начинается обработка захваченного мейлбокса с квотой старого мейлбокса
7) При завершении квоты, захваченный мейлбокс обрабатывается как в Send<ESendingType::Lazy>
Требуется когда важно продолжить цепочку работы в следующем акторе пока кеши сообщения еще прогреты. По сравнению с Send<ESendingType::Lazy> гарантировано продолжит обработку сообщения и не имеет проблем с задержкой обработки сообщения.
|