2017-06-27 40 views
2

我發現了一種快速匹配二進制幀的方法。 長度與整數和部分c(有效負載)相匹配的長度與長度字段中聲明的八位字節數一樣多。 (前三個八位字節)在解析HTTP/2.0幀的elixir二進制文件中匹配多個部分

<<length::24, b::48, c::binary-size(length)>> <> rest = buffer 

問題是得到我的幀我需要重新組合部分。

frame = <<length::24, b::48, c::binary>> 

有沒有辦法在原始匹配中分配幀變量。像下面這樣。 儘管這種精確的版本不起作用

(frame = <<length::24, _::48, _::binary-size(length)>>) <> rest = buffer 

編輯,或一些類似下面的語法也將使意義

<< frame = <<length::24, _::48, _::binary-size(length)>>, rest::binary>> 
+0

您可能已經知道這一點,但爲了防止重新創建二進制文件,可以使用':binary.part(buffer,0,3 + 6 + length)'。 ':binary.part/3'將從原始'buffer'中創建一個子二進制文件,而不是分配一個新的二進制文件。 – Dogbert

+0

我不知道這聽起來有幫助,仍然是一個兩步驟的過程來獲得我想要的二進制文件,但很可能非常快 –

回答

1

AFAIK,這是不可能的正是這種方式,但你可能會宣佈一個方便的助手爲避免重複輸入:

def matcher(buffer) 
    with <<length::24, b::48, c::binary-size(length), rest::binary>> <- buffer do 
    {:ok, <<length::24, b::48, c::binary-size(length)>>, rest} 
    else 
    other -> {:error, other} 
    end 
end 

而且使用它像:

{:ok, frame, rest} = matcher(buffer) 
+0

謝謝,不想聽起來不值得,但我已經得到了這麼多:-)。我想知道是否有一條線是可能的,因爲它可能更具性能。沒有創建和連接臨時二進制文件 –

0

我不明白b::48表示的標題的哪一部分。

但無論如何,性能明智的考慮幾件事情是很重要的。

  1. 你沒有通過返回一個幀二進制的性能。如果您已經解析了框架並知道它已完成,則將其作爲etf表示法返回。不要重新解析它。
  2. 一行不一定更高性能。這一切都是以某種方式組合和提取二進制文件。
  3. 函數定義中的模式匹配也是非常高效的,儘可能爲不同的代碼路徑做到這一點。

我不知道性能<>真的是如何。我認爲這只是速記,但即使它不同,它也可能足夠高效。

這段代碼應該創建並鏈接二進制部分,不應該創建任何新的二進制文件。因此它實際上是非常高效的。

<<length::24, b::48, c::binary-size(length), rest::binary>> = buffer 
frame = <<length::24, b::48, c::binary>> 

如果你想看到我是如何處理這種數據,那麼看看WebSockex.Frame

+0

你確定'frame = << length :: 24,b :: 48,c :: binary >>'會共享原始二進制嗎?我剛剛創建了一個1兆字節的緩衝區,其中包含一個幀,並創建了一個100「<< length :: 24,b :: 48,c :: binary >>'的列表,並且我的內存使用量增加了100MB。另一方面,如果我創建一個100'frame =:binary.part(buffer,0,9999999)'的列表,我的內存使用率保持不變。 – Dogbert

+0

是的,但它是一個編譯時優化。請參閱[Erlang二進制處理](http://erlang.org/doc/efficiency_guide/binaryhandling.html)頁上的**匹配上下文**。 – Azolo