Wenn 3 Clients die Funktion gleichzeitig aufrufen, erhöht die Funktion den Zähler nur einmal und ich erhalte einen Fehler. Wie lasse ich die Funktion warten, bis eine andere beendet und dann ausgeführt wird?
Ich würde einen einfachen Zähler mit gen_server
gebaut und nur den Zähler auf der Festplatte von ihm zugreifen. Mit einer gen_server
wie dieser würde sichergestellt, dass Sie nie eine Dateizugriff Race-Bedingung erhalten.
Hier ist etwas für den Anfang:
-module(file_counter).
-export([start_link/0, start/0, increment/0]).
-behaviour(gen_server).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
start() ->
gen_server:start({local, ?MODULE}, ?MODULE, [], []).
increment() ->
gen_server:call(?MODULE, increment).
init([]) ->
{ok, "file_counter.txt"}.
handle_call(increment, _From, File) ->
Counter = case file:read_file(File) of
{ok, Binary} -> binary_to_integer(Binary);
{error, enoent} -> 0
end,
ok = file:write_file(File, integer_to_binary(Counter + 1)),
{reply, Counter, File}.
handle_cast(_Req, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
Demo:
1> c(file_counter).
{ok,file_counter}
2> file_counter:start_link().
{ok,<0.40.0>}
3> file_counter:increment().
0
4> file_counter:increment().
1
5> file_counter:increment().
2
6> [ spawn_link(file_counter, increment, []) || _ <- lists:seq(1, 9998) ].
[<0.45.0>,<0.46.0>,<0.47.0>,<0.48.0>,<0.49.0>,<0.50.0>,
<0.51.0>,<0.52.0>,<0.53.0>,<0.54.0>,<0.55.0>,<0.56.0>,
<0.57.0>,<0.58.0>,<0.59.0>,<0.60.0>,<0.61.0>,<0.62.0>,
<0.63.0>,<0.64.0>,<0.65.0>,<0.66.0>,<0.67.0>,<0.68.0>,
<0.69.0>,<0.70.0>,<0.71.0>,<0.72.0>,<0.73.0>|...]
7> file_counter:increment().
10001
Rufen Sie file_counter:increment()
vor jedem Gespräch und den Wert, indem sie es als die Zählung wieder verwenden.
Edit: Dies ist nur ein schnelles Modul, das ich schrieb. Sie sollten den Dateinamen möglicherweise konfigurierbar machen, indem Sie ihn an start
, start_link
und übergeben, und den Prozess nicht mit einem Namen registrieren, wenn Sie mehrere Kopien des Zählers ausführen möchten. Der Code hier ist wirklich ein POC, um loszulegen.
(Auf einem System mit einer SSD Festplatte, war ich in der Lage file_counter:increment()
etwa 5000-mal pro Sekunde auszuführen.)
Effizienter wäre den Zähler beim Start zu lesen und speichern sie in ETS (oder ein Stateful-Prozess) , und schreibe es dann beim Herunterfahren zurück. Jedoch: das ist nicht 100% zuverlässig. Was passiert, wenn Sie mehrere Anrufe "vergessen" und versuchen, mit einer früheren Nummer anzurufen? –
Der Webservice gibt eine Art von Fehler zurück und die folgenden Aufrufe ergeben keinen Sinn. Deshalb ist es so wichtig, den Zähler richtig zu halten. –
@Roger Lipscombe –