Когда вы материализуете поток, ActorMaterializer
решает, как запускать различные этапы.По умолчанию все этапы выполняются последовательно внутри одного и того же актера за кулисами.Это сделано для того, чтобы избежать издержек переключения контекста потока, которые могут возникнуть, если каждый этап будет выполняться в отдельном акторе.
Когда вы используете оператор async
на этапе, вы сообщаете материализатору, что вы хотитесоздать асинхронную границу в этой точке.Это означает, что сцена будет работать в своем собственном актере за кулисами.В зависимости от сценария это может повлиять на производительность, поскольку события будут пересекать асинхронные границы.
Например:
Source(List("A","B","C "))
.map(x => x.toLowerCase)
.async
.map(x => x.toUpperCase)
.map(x => x.trim)
.runWith(Sink.ignore)
Этот поток будет запускать этап map(x => x.toLowerCase)
в другом действующем субъекте, чем этапыmap(x => x.toUpperCase)
и map(x => x.trim)
.Последние два будут выполняться внутри одного и того же действующего лица.
Последнее, что следует упомянуть, это то, что асинхронные границы также позволяют обрабатывать события параллельно внутри потока.Каждая асинхронная граница может обрабатывать события независимо, так как они выполняются в разных субъектах (до тех пор, пока есть спрос из нисходящего потока).В этом простом сценарии «B» может обрабатываться на map(x => x.toLowerCase)
одновременно с «A» на map(x => x.toUpperCase)
и map(x => x.trim)
.
Я надеюсь, что это поможет понять немного больше о том, как работают потоки.