• Keine Ergebnisse gefunden

Streams. Это тоже можно стримить. Евгений Галкин

N/A
N/A
Protected

Academic year: 2022

Aktie "Streams. Это тоже можно стримить. Евгений Галкин"

Copied!
49
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

25.11.2021 Евгений Галкин

Это тоже можно стримить

Streams

(2)

Евгений Галкин

• Разработчик в Тинькофф

• Java 10 лет

• Scala 1 год

• Делаю телефонного секретаря Олега

(3)

Задача – Преобразовать аудио файл в текст

3

Аудио Файл

@OlegOtvetBot

(4)

Задача – Преобразовать аудио файл в текст

4

Хранилище записей

Имя файла

Record.ogg Конвертация

в Wav Распознавание

в текст Файл

Record.ogg Файл

Record.wav Текст

разговора

(5)

Задача – Преобразовать аудио файл в текст

5

Хранилище записей

Имя файла

Record.ogg Конвертация

в Wav Распознавание

в текст Файл

Record.ogg Файл

Record.wav Текст

разговора

(6)

Задача – Преобразовать аудио файл в текст

6

Хранилище записей

Имя файла

Record.ogg Конвертация

в Wav Распознавание

в текст Файл

Record.ogg Файл

Record.wav Текст

разговора

(7)

Задача – Преобразовать аудио файл в текст

7

Хранилище записей

Имя файла

Record.ogg Конвертация

в Wav Распознавание

в текст Файл

Record.ogg Файл

Record.wav Текст

разговора

(8)

Extract Transform Load

Извлечение

данных Трансформация Загрузка

ETL

8

(9)

10s 10s 10s ???

Загрузить

файл Преобразовать

формат

Распознать в текст

Затрачено времени?

Время выполнения

9

(10)

10Mb >10Mb

Занимаемая память

10

(11)

10Mb >10Mb

Занимаемая память

11

10Mb >10Mb

10Mb >10Mb

>30Mb

(12)

100Mb >100Mb

Занимаемая память

12

10Mb >10Mb

1000Mb >1000Mb

>1110Mb

(13)

Классический подход

13

§ Легкий, простой

императивный код

§ Долго

§ Много и не предсказуемо по памяти

Streams

§ Простой функциональный код

§ Быстро

§ Мало и предсказуемо по

памяти

(14)

Загрузить

файл Преобразовать

формат

Распознать в текст

Время выполнения

14

Файл Результат

(15)

Загрузить

файл Преобразовать

формат

Распознать в текст

Время выполнения

15

Файл Результат

1S

(16)

Загрузить

файл Преобразовать

формат

Распознать в текст

Время выполнения

16

Файл Результат

1S 1S

(17)

Загрузить

файл Преобразовать

формат

Распознать в текст

Время выполнения

17

Файл Результат

1S 1S 1S

(18)

Загрузить

файл Преобразовать

формат

Распознать в текст

Занимаемая память

18

Файл Результат

4Kb 4Kb 4Kb

(19)

Инструменты

19

§ ZIO Streams

§ FS2 Streams

§ Akka Streams

(20)

Библиотеки

20

§ Doobie ( Database )

§ Tapir ( Http server ) (Akka, Http4s, ZIO Http )

§ Sttp ( Http client ) (Akka, AsyncHttpClient, Armeria, Http4s, HttpClient )

(21)

Создание

21

Stream.empty

Stream.succeed(22)

Stream.fromEffect(ZIO.succeed(22)) Stream.apply(1, 2, 3)

Stream.fromChunk(Chunk(1, 2, 3)) Stream.fromIterable(List(1, 2, 3)) Stream.range(1, 10)

Stream.iterate(1)(_ + 1)

(22)

Преобразование

22

Stream(1, 2, 3) .map(_ + 1)

.mapM(a => ZIO.succeed(a + 1))

.flatMap(a => Stream.succeed((a + 1))) .mapChunks(chunk => chunk)

.mapMPar(3)(a => ZIO.succeed(a + 1))

.flatMapPar(3)(a => Stream.succeed(a + 1)) .take(2)

.drop(1)

(23)

Разделение и объединение

23

Stream(1, 2, 3).partition(_ % 2 == 0) Stream(1, 2, 3).merge(Stream(4, 5, 6))

(24)

Выполнение

24

Stream(1, 2, 3).foreach(a => console.putStrLn(s"$a")) Stream(1, 2, 3).runHead

Stream(1, 2, 3).runDrain

Stream(1, 2, 3).fold(0)(_ + _)

(25)

Queue

25

for {

queue <- Queue.unbounded[Int]

stream = Stream.fromQueue(queue)

fiber <- stream.tap(value => console.putStrLn(s"$value")).take(1).runDrain.fork _ <- queue.offer(22)

_ <- fiber.join } yield ()

(26)

Doobie

26

import zio.interop.catz._

import zio.stream.interop.fs2z._

val transactor: Transactor[Task] = ???

val stream = sql"select name from country"

.query[String]

.stream

.transact(transactor) .toZStream()

stream.tap(value => console.putStrLn(s"$value")).take(1).runDrain

(27)

Doobie

27

import zio.interop.catz._

import zio.stream.interop.fs2z._

val transactor: Transactor[Task] = ???

val stream = sql"select name from country"

.query[String]

.stream

.transact(transactor) .toZStream()

stream.tap(value => console.putStrLn(s"$value")).take(1).runDrain

(28)

Sttp отправка

28

val stream: Stream[Throwable, Byte] = Stream.succeed(22)

val request = basicRequest

.streamBody(ZioStreams)(stream) .post(uri"http://...")

request.send(backend)

(29)

Sttp получение

29

val request = basicRequest

.post(uri"http://...")

.response(asStreamAlwaysUnsafe(ZioStreams)) .readTimeout(Duration.Inf)

for {

response <- request.send(backend).orDie stream = response.body

_ <- stream.tap(value => console.putStrLn(s"$value")).take(1).runDrain } yield ()

(30)

Java IO Interop

(31)

Java IO Interop

31

§ InputStream ( Читаем )

§ OutputStream ( Пишем )

int read() throws IOException;

void write(int b) throws IOException;

(32)

Streams в InputStream

32

def read(inputStream: InputStream): Unit = ???

val managed = for {

inputStream <- Stream.succeed[Byte](22).toInputStream

_ <- blocking.effectBlockingIO(send(inputStream)).toManaged_

} yield ()

managed.useNow

(33)

Managed

33

val managedStream: Managed[Any, InputStream] = Stream.succeed[Byte](22).toInputStream

def make[R, R1 <: R, E, A](acquire: ZIO[R, E, A])(release: A => ZIO[R1, Nothing, Any]): ZManaged[R1, E, A]

Managed.make(blocking.effectBlockingIO(new FileInputStream("file.txt")))(stream =>

blocking.effectBlockingIO(stream.close).ignore)

(34)

InputStream в Streams

34

def read(): InputStream = ???

val managed = ZManaged.fromAutoCloseable(blocking.effectBlockingIO(load())) val stream = Stream.fromInputStreamManaged(managed)

stream.tap(value => console.putStrLn(s"$value")).take(1).runDrain

(35)

Streams из OutputStream

35

def write(outputStream: OutputStream): Unit = ???

val stream = ZStream.fromOutputStreamWriter(outputStream => write(outputStream)) stream.tap(value => console.putStrLn(s"$value")).take(1).runDrain

(36)

File

36

Stream.fromFile(Paths.get("file.txt"))

Stream.fromFile(Paths.get("file.txt"), chunkSize = 4096) Stream.fromResource("file.txt")

Stream.fromReader(new FileReader("file.txt"))

(37)

gRPC Bidirectional

Streaming over HTTP/2

(38)

Streams gRPC

38

service SpeechToText {

rpc StreamingRecognize(stream StreamingRecognizeRequest) returns (stream StreamingRecognizeResponse);

}

Распознавайте и синтезируйте речь с VoiceKit https://voicekit.tinkoff.ru/

(39)

Streams gRPC

39

val client: SpeechToTextClient.ZService[Any, Any] = ???

val stream = Stream.succeed[Byte](22)

val config = Stream.succeed(

StreamingRecognizeRequest(

StreamingRequest.StreamingConfig(

StreamingRecognitionConfig(Some(RecognitionConfig(AudioEncoding.LINEAR16, sampleRateHertz = 48000, numChannels = 1))) )

) )

val data =

stream.mapChunks(chunk => Chunk(StreamingRecognizeRequest(StreamingRequest.AudioContent(ByteString.copyFrom(chunk.toArray))))) val textStream = client.streamingRecognize(config ++ data)

val text = textStream.fold("")((acc, response) =>

acc + response.results.flatMap(result => result.recognitionResult.flatMap(_.alternatives)).mkString(" ") )

(40)

Streams gRPC

40

val client: SpeechToTextClient.ZService[Any, Any] = ???

val stream = Stream.succeed[Byte](22)

val config = Stream.succeed(

StreamingRecognizeRequest(

StreamingRequest.StreamingConfig(

StreamingRecognitionConfig(Some(RecognitionConfig(AudioEncoding.LINEAR16, sampleRateHertz = 48000, numChannels = 1))) )

) )

val data =

stream.mapChunks(chunk => Chunk(StreamingRecognizeRequest(StreamingRequest.AudioContent(ByteString.copyFrom(chunk.toArray))))) val textStream = client.streamingRecognize(config ++ data)

val text = textStream.fold("")((acc, response) =>

acc + response.results.flatMap(result => result.recognitionResult.flatMap(_.alternatives)).mkString(" ") )

(41)

Streams gRPC

41

val client: SpeechToTextClient.ZService[Any, Any] = ???

val stream = Stream.succeed[Byte](22)

val config = Stream.succeed(

StreamingRecognizeRequest(

StreamingRequest.StreamingConfig(

StreamingRecognitionConfig(Some(RecognitionConfig(AudioEncoding.LINEAR16, sampleRateHertz = 48000, numChannels = 1))) )

) )

val data =

stream.mapChunks(chunk => Chunk(StreamingRecognizeRequest(StreamingRequest.AudioContent(ByteString.copyFrom(chunk.toArray))))) val textStream = client.streamingRecognize(config ++ data)

val text = textStream.fold("")((acc, response) =>

acc + response.results.flatMap(result => result.recognitionResult.flatMap(_.alternatives)).mkString(" ") )

(42)

Streams gRPC

42

val client: SpeechToTextClient.ZService[Any, Any] = ???

val stream = Stream.succeed[Byte](22)

val config = Stream.succeed(

StreamingRecognizeRequest(

StreamingRequest.StreamingConfig(

StreamingRecognitionConfig(Some(RecognitionConfig(AudioEncoding.LINEAR16, sampleRateHertz = 48000, numChannels = 1))) )

) )

val data =

stream.mapChunks(chunk => Chunk(StreamingRecognizeRequest(StreamingRequest.AudioContent(ByteString.copyFrom(chunk.toArray))))) val textStream = client.streamingRecognize(config ++ data)

val text = textStream.fold("")((acc, response) =>

acc + response.results.flatMap(result => result.recognitionResult.flatMap(_.alternatives)).mkString(" ") )

(43)

Наша программа

43

val filenames = List("file1.ogg", "file2.ogg", "file3.ogg")

def loadFile(filename: String): UStream[Byte] = ???

def convert(inputStream: UStream[Byte]): UStream[Byte] = ???

def recognize(inputStream: UStream[Byte]): UStream[String] = ???

Stream

.fromIterable(filenames)

.flatMapPar(3)(filename => recognize(convert(loadFile(filename)))) .tap(line => console.putStrLn(line))

.runDrain

(44)

Наша программа

44

val filenames = List("file1.ogg", "file2.ogg", "file3.ogg")

def loadFile(filename: String): UStream[Byte] = ???

def convert(inputStream: UStream[Byte]): UStream[Byte] = ???

def recognize(inputStream: UStream[Byte]): UStream[String] = ???

Stream

.fromIterable(filenames)

.flatMapPar(3)(filename => recognize(convert(loadFile(filename)))) .tap(line => console.putStrLn(line))

.runDrain

(45)

Наша программа

45

val filenames = List("file1.ogg", "file2.ogg", "file3.ogg")

def loadFile(filename: String): UStream[Byte] = ???

def convert(inputStream: UStream[Byte]): UStream[Byte] = ???

def recognize(inputStream: UStream[Byte]): UStream[String] = ???

Stream

.fromIterable(filenames)

.flatMapPar(3)(filename => recognize(convert(loadFile(filename)))) .tap(line => console.putStrLn(line))

.runDrain

(46)

Наша программа

46

val filenames = List("file1.ogg", "file2.ogg", "file3.ogg")

def loadFile(filename: String): UStream[Byte] = ???

def convert(inputStream: UStream[Byte]): UStream[Byte] = ???

def recognize(inputStream: UStream[Byte]): UStream[String] = ???

Stream

.fromIterable(filenames)

.flatMapPar(3)(filename => recognize(convert(loadFile(filename)))) .tap(line => console.putStrLn(line))

.runDrain

(47)

Наша программа

47

val filenames = List("file1.ogg", "file2.ogg", "file3.ogg")

def loadFile(filename: String): UStream[Byte] = ???

def convert(inputStream: UStream[Byte]): UStream[Byte] = ???

def recognize(inputStream: UStream[Byte]): UStream[String] = ???

Stream

.fromIterable(filenames)

.flatMapPar(3)(filename => recognize(convert(loadFile(filename)))) .tap(line => console.putStrLn(line))

.runDrain

(48)

Классический подход

48

§ Легкий, простой код

§ Долго

§ Много и не предсказуемо по памяти

Streams

§ Легкий, простой код

§ Быстро

§ Мало и предсказуемо по памяти

§ Подходит для задач, где

данные можно обрабатывать

последовательно

(49)

tinkoff.ru

Евгений Галкин

tinkoff.ru

Полезные ссылки

Referenzen

ÄHNLICHE DOKUMENTE

We identify representative roles involved in globally distributed requirements elicitation and provide each role with a view of the method chunk relevant to him/her.. We

Da nun diese Verschraubeinheit für diesen Arbeitsbereich deklariert wurde, muss die Funktion aktiviert werden, damit das Werkzeug laufen kann.. Rufen Sie die

Wenn keine individuellen Einstellungen für einen Benutzer vorliegen, prüft der ELO Web Client, ob der Benutzer sich in einer Optionengruppe befindet.. Trifft dies zu, gelten

Wenn keine individuellen Einstellungen für einen Benutzer vorliegen, prüft der ELO Web Client, ob der Benutzer sich in einer Optionengruppe befindet.. Trifft dies zu, gelten

Lassen Sie Ihre Teilnehmenden Wörter bestimmten Kategorien zuordnen und machen Sie im Unterricht Chunk-Runden 15 : je öfter bestimmte Wörter in Verbindung miteinander

In the second simulation experiment, we replaced one-hot encoding of semantic vec- tors with the distributional vectors of the Tasa1 semantic space. Figure 4 illustrates that

Wenn keine individuellen Einstellungen für einen Benutzer vorliegen, prüft der ELO Web Client, ob der Benutzer sich in einer Optionengruppe befindet.. Trifft dies zu, gelten

We manipulated literary and non-literary passages so that the modified versions had lower word chunk frequencies but higher individual word frequencies than