SlideShare uma empresa Scribd logo
1 de 28
Baixar para ler offline
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

Mais conteúdo relacionado

Mais de Elixir Club

Mais 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
 

Último

Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 

Último (20)

Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
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
 
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...
 
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
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
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...
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 

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]