Erlang:以有效的方式从输入流中读取

Sal*_*rit 5 io erlang performance inputstream processing-efficiency

我正在编写一个从输入流中读取的程序,即

erl -run p main -noshell -s erlang halt < input
Run Code Online (Sandbox Code Playgroud)

问题是使用这个读取函数需要花费大量时间来读取它(输入流很大):

read_input(L) ->
    case io:get_line("") of
        eof ->
            lists:reverse(L);
        E0 ->
            read_input([E0|L])
    end.
Run Code Online (Sandbox Code Playgroud)

我一直在寻找更有效的替代方案,但我一无所获.我试过用它来读取文件

{ok, Binary} = file:read_file("input")
Run Code Online (Sandbox Code Playgroud)

这远远高效得多.问题是我必须在名称未知的平台上运行此程序,所以我需要一些替代方法来执行此操作.另外,我无法选择运行时使用的标志,例如,标志-noinput无法添加到命令行.

无论您给予什么帮助,都会受到欢迎.

Ste*_*ski 8

您可以使用它open_port/2来打开stdin并从中读取二进制文件.例如:

-module(p).
-export([start/0]).

start() ->
    process_flag(trap_exit, true),
    P = open_port({fd,0,1}, [in, binary]),
    Bin = read(P,<<>>),
    io:format("received ~p\n", [Bin]),
    halt(0).

read(P, Bin) ->
    receive
        {P, {data, Data}} ->
            read(P, <<Bin/binary, Data/binary>>);
        {'EXIT',P,_} ->
            Bin
    end.
Run Code Online (Sandbox Code Playgroud)

代码必须捕获出口,因此它知道在端口关闭时退出其读取循环.此示例将所有内容读入从read/2函数返回的单个二进制文件中,然后将其打印出来并退出,但显然您可以在实际应用程序中对二进制文件执行进一步操作.

你可以像这样运行:

erl -noinput -s p < input
Run Code Online (Sandbox Code Playgroud)

  • 你的问题表明你正在使用`-noshell`.为什么你可以使用它但你不能使用`-noinput`?你真的需要在你的问题中明确你的要求. (2认同)

Hyn*_*dil 3

尽管史蒂夫的 解决方案是我所知最快的解决方案,但可以使用file具有相当好的性能的模块解决方案:

-module(p).

-export([start/0]).

-define(BLK_SIZE, 16384).

start() ->
    do(),
    halt().

do() ->
    Bin = read(),
    io:format("~p~n", [byte_size(Bin)]).

read() ->
    ok = io:setopts(standard_io, [binary]),
    read(<<>>).

read(Acc) ->
    case file:read(standard_io, ?BLK_SIZE) of
        {ok, Data} ->
            read(<<Acc/bytes, Data/bytes>>);
        eof ->
            Acc
    end.
Run Code Online (Sandbox Code Playgroud)

它可以与如下调用一起使用:

erl -noshell -s p < input
Run Code Online (Sandbox Code Playgroud)

请注意,两种方法都可用于使用{line, Max_Line_Size}端口或模块解决方案选项的file:read_line/1面向行的输入file。从版本 17 开始(如果我没记错的话),我发现存在固定的性能错误,file:read_line/1所以现在很好。无论如何,您不应该期望 Perl 的性能和舒适性。