Skip to content

Commit

Permalink
Finch.request/3: Use improper list and avoid Enum.reverse
Browse files Browse the repository at this point in the history
I tried benchmarking this and it's inconclusive but I think conceptually
it makes more sense.

    {:ok, _} =
      Bandit.start_link(
        port: 4000,
        plug: fn conn, _ ->
          conn = Plug.Conn.send_chunked(conn, 200)

          Enum.reduce(1..1000, conn, fn _, conn ->
            {:ok, conn} = Plug.Conn.chunk(conn, String.duplicate("0", 1000))
            conn
          end)
        end
      )

    {:ok, _} = Finch.start_link(name: :a)
    {:ok, _} = Finch.start_link(name: :b)

    req = Finch.build(:get, "http://localhost:4000")

    Benchee.run(
      %{
        "a" => fn ->
          fun = fn
            {:status, value}, {_, headers, body, trailers} ->
              {:cont, {value, headers, body, trailers}}

            {:headers, value}, {status, headers, body, trailers} ->
              {:cont, {status, headers ++ value, body, trailers}}

            {:data, value}, {status, headers, body, trailers} ->
              {:cont, {status, headers, [value | body], trailers}}

            {:trailers, value}, {status, headers, body, trailers} ->
              {:cont, {status, headers, body, trailers ++ value}}
          end

          {:ok, {200, _headers, body, _trailers}} =
            Finch.stream_while(req, :a, {nil, [], [], []}, fun)

          body |> Enum.reverse() |> IO.iodata_to_binary() |> byte_size()
        end,
        "b" => fn ->
          fun = fn
            {:status, value}, {_, headers, body, trailers} ->
              {:cont, {value, headers, body, trailers}}

            {:headers, value}, {status, headers, body, trailers} ->
              {:cont, {status, headers ++ value, body, trailers}}

            {:data, value}, {status, headers, body, trailers} ->
              {:cont, {status, headers, [body | value], trailers}}

            {:trailers, value}, {status, headers, body, trailers} ->
              {:cont, {status, headers, body, trailers ++ value}}
          end

          {:ok, {200, _headers, body, _trailers}} =
            Finch.stream_while(req, :b, {nil, [], [], []}, fun)

          body |> IO.iodata_to_binary() |> byte_size()
        end
      },
      time: 10,
      memory_time: 2
    )

Results:

    12:00:04.273 [info] Running #Function<0.20032135 in file:bench.exs> with Bandit 1.5.3 at 0.0.0.0:4000 (http)
    Operating System: macOS
    CPU Information: Apple M2
    Number of Available Cores: 8
    Available memory: 24 GB
    Elixir 1.18.0-dev
    Erlang 27.0.1
    JIT enabled: true

    Benchmark suite executing with the following configuration:
    warmup: 2 s
    time: 10 s
    memory time: 2 s
    reduction time: 0 ns
    parallel: 1
    inputs: none specified
    Estimated total run time: 28 s

    Benchmarking a ...
    Benchmarking b ...
    Calculating statistics...
    Formatting results...

    Name           ips        average  deviation         median         99th %
    a            95.77       10.44 ms     ±2.19%       10.43 ms       11.21 ms
    b            95.43       10.48 ms     ±2.02%       10.46 ms       11.13 ms

    Comparison:
    a            95.77
    b            95.43 - 1.00x slower +0.0377 ms

    Memory usage statistics:

    Name         average  deviation         median         99th %
    a            2.24 MB     ±0.50%        2.24 MB        2.25 MB
    b            2.23 MB     ±0.35%        2.23 MB        2.24 MB

    Comparison:
    a            2.24 MB
    b            2.23 MB - 1.00x memory usage -0.01002 MB
  • Loading branch information
wojtekmach committed Aug 5, 2024
1 parent 59e035b commit 4bedff4
Showing 1 changed file with 2 additions and 2 deletions.
4 changes: 2 additions & 2 deletions lib/finch.ex
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ defmodule Finch do
{:cont, {status, headers ++ value, body, trailers}}

{:data, value}, {status, headers, body, trailers} ->
{:cont, {status, headers, [value | body], trailers}}
{:cont, {status, headers, [body | value], trailers}}

{:trailers, value}, {status, headers, body, trailers} ->
{:cont, {status, headers, body, trailers ++ value}}
Expand All @@ -495,7 +495,7 @@ defmodule Finch do
%Response{
status: status,
headers: headers,
body: body |> Enum.reverse() |> IO.iodata_to_binary(),
body: IO.iodata_to_binary(body),
trailers: trailers
}}
end
Expand Down

0 comments on commit 4bedff4

Please # to comment.