SlideShare une entreprise Scribd logo
1  sur  28
Télécharger pour lire hors ligne
Experimental.Flow
An overview of experimental Elixir Flow module that allows developers
to express processing steps for collections, like Stream, but utilizing the
power of parallel execution.
Resources
ElixirConf 2016 - Keynote by José Valim
www.youtube.com/watch?v=srtMWzyqdp8
Kyiv Elixir Meetup 3 - Flow-Based Programming with Elixir, Anton
Mishchuk
www.youtube.com/watch?v=yDaPaCxAVq8
www.slideshare.net/AntonMishchuk/flowbased-programming-with-
elixir
Resources
Announcing GenStage
elixir-lang.org/blog/2016/07/14/announcing-genstage/
gen_stage
hex.pm/packages/gen_stage
https://hexdocs.pm/gen_stage/
https://hexdocs.pm/gen_stage/Experimental.Flow.html
Task
Implement word counting algorithm using Eager, Lazy and Concurrent
approaches
• Eager – Enum
• Lazy – Stream
• Concurrent - Flow
Eager
+ High processing speed (for small collections)
- May require large amounts of memory
Good for fast processing of small collections
Eager (Enum)
def process_eager(path_to_file) do
path_to_file
|> File.read!()
|> String.split()
|> Enum.reduce(%{}, &words_to_map/2)
end
Helper functions
defp words_to_map(word, map) do
word
|> String.replace(~r/W/u, "")
|> filter_map(map)
end
defp filter_map("", map), do: map
defp filter_map(word, map) do
word = String.downcase(word)
Map.update(map, word, 1, &(&1 + 1))
end
Lazy (Stream)
+ Allows us to “control” memory consumption
- Processing overhead
Allows us to work with large datasets without loading them all into
memory
Lazy (Stream)
def process_lazy(path_to_file) do
path_to_file
|> File.stream!()
|> Stream.flat_map(&String.split/1)
|> Enum.reduce(%{}, &words_to_map/2)
end
Concurrent (Flow)
+ Concurrency
+ Allows us to “control” memory consumption
- Processing overhead
Allows us to process large or infinite collections concurrently on
multicore machines
GenStage is a new Elixir behaviour for exchanging events
with back-pressure between Elixir processes
producer
producer
consumer
producer
consumer
consumer
GenStage: demand-driven message exchange
producer
producer
consumer
consumer
Asks 10
Sends 10 max Sends 10 max
Asks 10
Dispatcher defines how the events are dispatched to
multiple consumers
P
C
C
C
Dispatcher
DemandDispatcher - dispatches events according to a
demand
P
C
C
C
1, 2, 3, 4, 5, 6, 7
1, 4, 7
2, 5
3, 6
PartitionDispatcher - dispatches events according to a
hash
P
C
C
C
“a”, “b”, “c”, “a”,
“d”, “c”, “a”
“c”, “c”
“a”, “a”,
“a”, “d”
“b”
Concurrent (Flow)
def process_flow(path_to_file) do
path_to_file
|> File.stream!()
|> Flow.from_enumerable()
|> Flow.flat_map(&String.split/1)
|> Flow.map(&String.replace(&1, ~r/W/u, ""))
|> Flow.filter_map(fn w -> w != "" end, &String.downcase/1)
|> Flow.partition()
|> Flow.reduce(fn -> %{} end, fn word, map ->
Map.update(map, word, 1, &(&1 + 1))
end)
|> Enum.into(%{})
end
Concurrent (Flow)
def process_flow(path_to_file) do
path_to_file
|> File.stream!()
|> Flow.from_enumerable()
|> Flow.flat_map(&String.split/1)
|> Flow.map(&String.replace(&1, ~r/W/u, ""))
|> Flow.filter_map(fn w -> w != "" end, &String.downcase/1)
|> Flow.partition()
|> Flow.reduce(fn -> %{} end, fn word, map ->
Map.update(map, word, 1, &(&1 + 1))
end)
|> Enum.into(%{})
end
P
Concurrent (Flow)
def process_flow(path_to_file) do
path_to_file
|> File.stream!()
|> Flow.from_enumerable()
|> Flow.flat_map(&String.split/1)
|> Flow.map(&String.replace(&1, ~r/W/u, ""))
|> Flow.filter_map(fn w -> w != "" end, &String.downcase/1)
|> Flow.partition()
|> Flow.reduce(fn -> %{} end, fn word, map ->
Map.update(map, word, 1, &(&1 + 1))
end)
|> Enum.into(%{})
end
P
PC PC
DemandDispatcher
Concurrent (Flow)
def process_flow(path_to_file) do
path_to_file
|> File.stream!()
|> Flow.from_enumerable()
|> Flow.flat_map(&String.split/1)
|> Flow.map(&String.replace(&1, ~r/W/u, ""))
|> Flow.filter_map(fn w -> w != "" end, &String.downcase/1)
|> Flow.partition()
|> Flow.reduce(fn -> %{} end, fn word, map ->
Map.update(map, word, 1, &(&1 + 1))
end)
|> Enum.into(%{})
end
P
PC PC
DemandDispatcher
PC PC
PartitionDispatcher
Concurrent (Flow)
def process_flow(path_to_file) do
path_to_file
|> File.stream!()
|> Flow.from_enumerable()
|> Flow.flat_map(&String.split/1)
|> Flow.map(&String.replace(&1, ~r/W/u, ""))
|> Flow.filter_map(fn w -> w != "" end, &String.downcase/1)
|> Flow.partition()
|> Flow.reduce(fn -> %{} end, fn word, map ->
Map.update(map, word, 1, &(&1 + 1))
end)
|> Enum.into(%{})
end
P
PC PC
DemandDispatcher
PartitionDispatcher
PC PC
C CReducers
%{} %{}
Concurrent (Flow)
def process_flow(path_to_file) do
path_to_file
|> File.stream!()
|> Flow.from_enumerable()
|> Flow.flat_map(&String.split/1)
|> Flow.map(&String.replace(&1, ~r/W/u, ""))
|> Flow.filter_map(fn w -> w != "" end, &String.downcase/1)
|> Flow.partition()
|> Flow.reduce(fn -> %{} end, fn word, map ->
Map.update(map, word, 1, &(&1 + 1))
end)
|> Enum.into(%{})
end
Concurrent (Flow): multiple sources
streams =
for file <- File.ls!(path_to_dir) do
File.stream!(path_to_dir <> "/" <> file,
read_ahead: 100_000)
end
Concurrent (Flow): multiple sources
streams
|> Flow.from_enumerables()
|> Flow.flat_map(&String.split/1)
|> Flow.map(&String.replace(&1, ~r/W/u, ""))
|> Flow.filter_map(fn w -> w != "" end, &String.downcase/1)
|> Flow.partition()
|> Flow.reduce(fn -> %{} end, fn word, map ->
Map.update(map, word, 1, &(&1 + 1))
end)
|> Enum.into(%{})
Concurrent (Flow): multiple sources
streams
|> Flow.from_enumerables()
|> Flow.flat_map(&String.split/1)
|> Flow.map(&String.replace(&1, ~r/W/u, ""))
|> Flow.filter_map(fn w -> w != "" end, &String.downcase/1)
|> Flow.partition()
|> Flow.reduce(fn -> %{} end, fn word, map ->
Map.update(map, word, 1, &(&1 + 1))
end)
|> Enum.into(%{})
FS
P P
FSFS
P
C
%{}
C
%{}
2 cores
3 files
Configuration (demand, the number of stages)
Flow.partition(stages: 8)
• :stages - the number of partitions (reducer stages)
• :hash - the hashing function
• :max_demand - the maximum demand for this subscription
• :min_demand - the minimum demand for this subscription
• …
Experimental.Flow.Window
Splits a flow into windows that are materialized at certain triggers.
window = Flow.Window.global
|> Flow.Window.trigger_every(10, :keep)
window = Flow.Window.global
|> Flow.Window.trigger_every(10, :reset)
Experimental.Flow.Window
Flow.from_enumerable(1..100)
|> Flow.partition(window: window, stages: 1)
|> Flow.reduce(fn -> 0 end, & &1 + &2)
|> Flow.emit(:state)
|> Enum.to_list()
keep> [55, 210, 465, 820, 1275, 1830, 2485, 3240, 4095, 5050,
5050]
reset> [55, 155, 255, 355, 455, 555, 655, 755, 855, 955, 0]
THANK YOU!!!
https://github.com/yuriibodarev/elixir_flow

Contenu connexe

Plus de Elixir Club

Plus de Elixir Club (20)

BEAM architecture handbook - Andrea Leopardi | Elixir Club Ukraine
BEAM architecture handbook - Andrea Leopardi  | Elixir Club UkraineBEAM architecture handbook - Andrea Leopardi  | Elixir Club Ukraine
BEAM architecture handbook - Andrea Leopardi | Elixir Club Ukraine
 
You ain't gonna need write a GenServer - Ulisses Almeida | Elixir Club Ukraine
You ain't gonna need write a GenServer - Ulisses Almeida  | Elixir Club UkraineYou ain't gonna need write a GenServer - Ulisses Almeida  | Elixir Club Ukraine
You ain't gonna need write a GenServer - Ulisses Almeida | Elixir Club Ukraine
 
— Knock, knock — An async templates — Who’s there? - Alexander Khokhlov | ...
 — Knock, knock — An async templates — Who’s there? - Alexander Khokhlov  |  ... — Knock, knock — An async templates — Who’s there? - Alexander Khokhlov  |  ...
— Knock, knock — An async templates — Who’s there? - Alexander Khokhlov | ...
 
Performance measurement methodology — Maksym Pugach | Elixir Evening Club 3
Performance measurement methodology — Maksym Pugach | Elixir Evening Club 3Performance measurement methodology — Maksym Pugach | Elixir Evening Club 3
Performance measurement methodology — Maksym Pugach | Elixir Evening Club 3
 
Erlang cluster. How is it? Production experience. — Valerii Vasylkov | Elixi...
Erlang cluster. How is it? Production experience. —  Valerii Vasylkov | Elixi...Erlang cluster. How is it? Production experience. —  Valerii Vasylkov | Elixi...
Erlang cluster. How is it? Production experience. — Valerii Vasylkov | Elixi...
 
Promo Phx4RailsDevs - Volodya Sveredyuk
Promo Phx4RailsDevs - Volodya SveredyukPromo Phx4RailsDevs - Volodya Sveredyuk
Promo Phx4RailsDevs - Volodya Sveredyuk
 
Web of today — Alexander Khokhlov
Web of today —  Alexander KhokhlovWeb of today —  Alexander Khokhlov
Web of today — Alexander Khokhlov
 
ElixirConf Eu 2018, what was it like? – Eugene Pirogov
ElixirConf Eu 2018, what was it like? – Eugene PirogovElixirConf Eu 2018, what was it like? – Eugene Pirogov
ElixirConf Eu 2018, what was it like? – Eugene Pirogov
 
Implementing GraphQL API in Elixir – Victor Deryagin
Implementing GraphQL API in Elixir – Victor DeryaginImplementing GraphQL API in Elixir – Victor Deryagin
Implementing GraphQL API in Elixir – Victor Deryagin
 
WebPerformance: Why and How? – Stefan Wintermeyer
WebPerformance: Why and How? – Stefan WintermeyerWebPerformance: Why and How? – Stefan Wintermeyer
WebPerformance: Why and How? – Stefan Wintermeyer
 
GenServer in Action – Yurii Bodarev
GenServer in Action – Yurii Bodarev   GenServer in Action – Yurii Bodarev
GenServer in Action – Yurii Bodarev
 
Russian Doll Paradox: Elixir Web without Phoenix - Alex Rozumii
Russian Doll Paradox: Elixir Web without Phoenix - Alex RozumiiRussian Doll Paradox: Elixir Web without Phoenix - Alex Rozumii
Russian Doll Paradox: Elixir Web without Phoenix - Alex Rozumii
 
Practical Fault Tolerance in Elixir - Alexei Sholik
Practical Fault Tolerance in Elixir - Alexei SholikPractical Fault Tolerance in Elixir - Alexei Sholik
Practical Fault Tolerance in Elixir - Alexei Sholik
 
Phoenix and beyond: Things we do with Elixir - Alexander Khokhlov
Phoenix and beyond: Things we do with Elixir - Alexander KhokhlovPhoenix and beyond: Things we do with Elixir - Alexander Khokhlov
Phoenix and beyond: Things we do with Elixir - Alexander Khokhlov
 
Monads are just monoids in the category of endofunctors - Ike Kurghinyan
Monads are just monoids in the category of endofunctors - Ike KurghinyanMonads are just monoids in the category of endofunctors - Ike Kurghinyan
Monads are just monoids in the category of endofunctors - Ike Kurghinyan
 
Craft effective API with GraphQL and Absinthe - Ihor Katkov
Craft effective API with GraphQL and Absinthe - Ihor KatkovCraft effective API with GraphQL and Absinthe - Ihor Katkov
Craft effective API with GraphQL and Absinthe - Ihor Katkov
 
Elixir in a service of government - Alex Troush
Elixir in a service of government - Alex TroushElixir in a service of government - Alex Troush
Elixir in a service of government - Alex Troush
 
Pattern matching in Elixir by example - Alexander Khokhlov
Pattern matching in Elixir by example - Alexander KhokhlovPattern matching in Elixir by example - Alexander Khokhlov
Pattern matching in Elixir by example - Alexander Khokhlov
 
Ecto and Phoenix: Doing web with Elixir - Yurii Bodarev
Ecto and Phoenix: Doing web with Elixir - Yurii BodarevEcto and Phoenix: Doing web with Elixir - Yurii Bodarev
Ecto and Phoenix: Doing web with Elixir - Yurii Bodarev
 
Handling external APIs with Elixir - Alex Rozumii
Handling external APIs with Elixir - Alex RozumiiHandling external APIs with Elixir - Alex Rozumii
Handling external APIs with Elixir - Alex Rozumii
 

Dernier

IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
Enterprise Knowledge
 

Dernier (20)

Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdf
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 

Experimental.flow - Yurii Bodarev

  • 1. Experimental.Flow An overview of experimental Elixir Flow module that allows developers to express processing steps for collections, like Stream, but utilizing the power of parallel execution.
  • 2. Resources ElixirConf 2016 - Keynote by José Valim www.youtube.com/watch?v=srtMWzyqdp8 Kyiv Elixir Meetup 3 - Flow-Based Programming with Elixir, Anton Mishchuk www.youtube.com/watch?v=yDaPaCxAVq8 www.slideshare.net/AntonMishchuk/flowbased-programming-with- elixir
  • 4. Task Implement word counting algorithm using Eager, Lazy and Concurrent approaches • Eager – Enum • Lazy – Stream • Concurrent - Flow
  • 5. Eager + High processing speed (for small collections) - May require large amounts of memory Good for fast processing of small collections
  • 6. Eager (Enum) def process_eager(path_to_file) do path_to_file |> File.read!() |> String.split() |> Enum.reduce(%{}, &words_to_map/2) end
  • 7. Helper functions defp words_to_map(word, map) do word |> String.replace(~r/W/u, "") |> filter_map(map) end defp filter_map("", map), do: map defp filter_map(word, map) do word = String.downcase(word) Map.update(map, word, 1, &(&1 + 1)) end
  • 8. Lazy (Stream) + Allows us to “control” memory consumption - Processing overhead Allows us to work with large datasets without loading them all into memory
  • 9. Lazy (Stream) def process_lazy(path_to_file) do path_to_file |> File.stream!() |> Stream.flat_map(&String.split/1) |> Enum.reduce(%{}, &words_to_map/2) end
  • 10. Concurrent (Flow) + Concurrency + Allows us to “control” memory consumption - Processing overhead Allows us to process large or infinite collections concurrently on multicore machines
  • 11. GenStage is a new Elixir behaviour for exchanging events with back-pressure between Elixir processes producer producer consumer producer consumer consumer
  • 12. GenStage: demand-driven message exchange producer producer consumer consumer Asks 10 Sends 10 max Sends 10 max Asks 10
  • 13. Dispatcher defines how the events are dispatched to multiple consumers P C C C Dispatcher
  • 14. DemandDispatcher - dispatches events according to a demand P C C C 1, 2, 3, 4, 5, 6, 7 1, 4, 7 2, 5 3, 6
  • 15. PartitionDispatcher - dispatches events according to a hash P C C C “a”, “b”, “c”, “a”, “d”, “c”, “a” “c”, “c” “a”, “a”, “a”, “d” “b”
  • 16. Concurrent (Flow) def process_flow(path_to_file) do path_to_file |> File.stream!() |> Flow.from_enumerable() |> Flow.flat_map(&String.split/1) |> Flow.map(&String.replace(&1, ~r/W/u, "")) |> Flow.filter_map(fn w -> w != "" end, &String.downcase/1) |> Flow.partition() |> Flow.reduce(fn -> %{} end, fn word, map -> Map.update(map, word, 1, &(&1 + 1)) end) |> Enum.into(%{}) end
  • 17. Concurrent (Flow) def process_flow(path_to_file) do path_to_file |> File.stream!() |> Flow.from_enumerable() |> Flow.flat_map(&String.split/1) |> Flow.map(&String.replace(&1, ~r/W/u, "")) |> Flow.filter_map(fn w -> w != "" end, &String.downcase/1) |> Flow.partition() |> Flow.reduce(fn -> %{} end, fn word, map -> Map.update(map, word, 1, &(&1 + 1)) end) |> Enum.into(%{}) end P
  • 18. Concurrent (Flow) def process_flow(path_to_file) do path_to_file |> File.stream!() |> Flow.from_enumerable() |> Flow.flat_map(&String.split/1) |> Flow.map(&String.replace(&1, ~r/W/u, "")) |> Flow.filter_map(fn w -> w != "" end, &String.downcase/1) |> Flow.partition() |> Flow.reduce(fn -> %{} end, fn word, map -> Map.update(map, word, 1, &(&1 + 1)) end) |> Enum.into(%{}) end P PC PC DemandDispatcher
  • 19. Concurrent (Flow) def process_flow(path_to_file) do path_to_file |> File.stream!() |> Flow.from_enumerable() |> Flow.flat_map(&String.split/1) |> Flow.map(&String.replace(&1, ~r/W/u, "")) |> Flow.filter_map(fn w -> w != "" end, &String.downcase/1) |> Flow.partition() |> Flow.reduce(fn -> %{} end, fn word, map -> Map.update(map, word, 1, &(&1 + 1)) end) |> Enum.into(%{}) end P PC PC DemandDispatcher PC PC PartitionDispatcher
  • 20. Concurrent (Flow) def process_flow(path_to_file) do path_to_file |> File.stream!() |> Flow.from_enumerable() |> Flow.flat_map(&String.split/1) |> Flow.map(&String.replace(&1, ~r/W/u, "")) |> Flow.filter_map(fn w -> w != "" end, &String.downcase/1) |> Flow.partition() |> Flow.reduce(fn -> %{} end, fn word, map -> Map.update(map, word, 1, &(&1 + 1)) end) |> Enum.into(%{}) end P PC PC DemandDispatcher PartitionDispatcher PC PC C CReducers %{} %{}
  • 21. Concurrent (Flow) def process_flow(path_to_file) do path_to_file |> File.stream!() |> Flow.from_enumerable() |> Flow.flat_map(&String.split/1) |> Flow.map(&String.replace(&1, ~r/W/u, "")) |> Flow.filter_map(fn w -> w != "" end, &String.downcase/1) |> Flow.partition() |> Flow.reduce(fn -> %{} end, fn word, map -> Map.update(map, word, 1, &(&1 + 1)) end) |> Enum.into(%{}) end
  • 22. Concurrent (Flow): multiple sources streams = for file <- File.ls!(path_to_dir) do File.stream!(path_to_dir <> "/" <> file, read_ahead: 100_000) end
  • 23. Concurrent (Flow): multiple sources streams |> Flow.from_enumerables() |> Flow.flat_map(&String.split/1) |> Flow.map(&String.replace(&1, ~r/W/u, "")) |> Flow.filter_map(fn w -> w != "" end, &String.downcase/1) |> Flow.partition() |> Flow.reduce(fn -> %{} end, fn word, map -> Map.update(map, word, 1, &(&1 + 1)) end) |> Enum.into(%{})
  • 24. Concurrent (Flow): multiple sources streams |> Flow.from_enumerables() |> Flow.flat_map(&String.split/1) |> Flow.map(&String.replace(&1, ~r/W/u, "")) |> Flow.filter_map(fn w -> w != "" end, &String.downcase/1) |> Flow.partition() |> Flow.reduce(fn -> %{} end, fn word, map -> Map.update(map, word, 1, &(&1 + 1)) end) |> Enum.into(%{}) FS P P FSFS P C %{} C %{} 2 cores 3 files
  • 25. Configuration (demand, the number of stages) Flow.partition(stages: 8) • :stages - the number of partitions (reducer stages) • :hash - the hashing function • :max_demand - the maximum demand for this subscription • :min_demand - the minimum demand for this subscription • …
  • 26. Experimental.Flow.Window Splits a flow into windows that are materialized at certain triggers. window = Flow.Window.global |> Flow.Window.trigger_every(10, :keep) window = Flow.Window.global |> Flow.Window.trigger_every(10, :reset)
  • 27. Experimental.Flow.Window Flow.from_enumerable(1..100) |> Flow.partition(window: window, stages: 1) |> Flow.reduce(fn -> 0 end, & &1 + &2) |> Flow.emit(:state) |> Enum.to_list() keep> [55, 210, 465, 820, 1275, 1830, 2485, 3240, 4095, 5050, 5050] reset> [55, 155, 255, 355, 455, 555, 655, 755, 855, 955, 0]