使用Erlang的httpc
通過HTTP下載文件時,CPU利用率遠高於curl或wget。我用來測量下載速度的代碼可以在這篇文章的底部看到。下載文件時的CPU利用率高
高CPU利用率問題尤其是在低端設備上。我在一個ARM-SoC上運行Erlang,它比第一個Raspberry PI稍微強大一些,而且這段代碼的CPU利用率高達100%,下載速度僅爲6.1 MiB/s。使用curl和wget,CPU利用率保持略低於100%,並且幾乎完全利用網絡接口 (100 MBit/s網絡接口上的10.7 MiB/s或85.6 MBit/s)。
我嘗試過使用其他HTTP庫,包括ibrowse和hackney,但同樣的問題仍然存在。我的猜測是它與Erlang的套接字性能有關,但我可能是錯的。所以我的問題是,究竟是什麼造成了這些緩慢的下載速度,並且是否有任何解決方法?我知道使用libcurl的庫如https://github.com/puzza007/katipo,因此可能不會有相同的問題,但我不希望使用任何使用NIF的庫。
defmodule DownloadPerformanceTest do
@testfile 'http://speed.hetzner.de/100MB.bin'
@filesize 104857600
@save_to '/dev/null'
def test() do
Application.start(:inets)
then = :erlang.system_time(:micro_seconds)
{:ok, :saved_to_file} = :httpc.request(:get, {@testfile, []}, [], [{:stream, @save_to}])
now = :erlang.system_time(:micro_seconds)
diff = now - then
bw = bandwidth_to_human_readable(@filesize, diff)
IO.puts "Download took #{:erlang.trunc(diff/1_000_000)} seconds, average speed: #{bw}"
end
defp bandwidth_to_human_readable(bytes, microseconds) do
bytes_per_second = bytes/(microseconds/1000000)
exponent = :erlang.trunc(:math.log2(bytes_per_second)/:math.log2(1024))
prefix = case exponent do
0 -> {:ok, ""}
1 -> {:ok, "Ki"}
2 -> {:ok, "Mi"}
3 -> {:ok, "Gi"}
4 -> {:ok, "Ti"}
5 -> {:ok, "Pi"}
6 -> {:ok, "Ei"}
7 -> {:ok, "Zi"}
8 -> {:ok, "Yi"}
_ -> {:error, :too_large}
end
case prefix do
{:ok, prefix} ->
quantity = Float.round(bytes_per_second/:math.pow(1024, exponent), 2)
unit = "#{prefix}B/s"
"#{quantity} #{unit}"
{:error, :too_large} ->
"#{bytes_per_second} B/s"
end
end
end
你有沒有試過這樣做只是一個套接字操作?我和httpc一起工作足以發現它有一些特質 - 但我不知道在http下載中會導致高CPU佔用率。就我的經驗而言,即使在受限的硬件上,Erlang的套接字性能也非常好,但我幾乎總是編寫純的套接字進程,而不使用其他協議庫,所以我不知道是否有任何低效率的HTTP數據傳輸正在進行也許HTTP塊和標題,而不是以相對昂貴的方式拆卸?)。 – zxq9
@ zxq9確實,使用:gen_tcp直接允許我以9.81 MiB/s的速度進行下載,而使用curl的速度爲10.5 MiB/s。我仍然更喜歡使用適當的HTTP庫,而不是重新發明輪子,但似乎幾乎所有維護良好的庫都基於hackney或ibrowse。 – helios35
在Erlang世界中,我們最近才真正開始關注HTTP,實際上,這只是其中的幾個地方 - 很多Erlang的工作通常與Web無關,並且也延伸到了文化領域。出於這個原因,我們從來沒有真正深入到本地的Erlang網絡庫或XML解析或瘋狂的HTML解析。我想這可能也適用於本地解析HTTP標頭,分塊等,作爲* strings *而不是在二進制文件和原子之間翻轉以及二進制到字符串轉換等。 – zxq9