Erlang模塊gen_server翻譯


gen_server

概要
  通用服務器行為
描述

  行為模塊實現服務器的客戶端-服務器關系。一個通用的服務器進程使用這個模塊將實現一組標准的接口功能,包括跟蹤和錯誤報告功能。它也符合OTP進程監控樹。了解更多信息參考OTP設計原則。

  gen_server假定所有特定部分位於一個回調模塊,它導出的一組預定義的功能。行為函數和回調函數的關系可以說明如下:

  gen_server module Callback module
  ----------------- ---------------
  gen_server:start_link -----> Module:init/1

  gen_server:call
  gen_server:multi_call -----> Module:handle_call/3

  gen_server:cast
  gen_server:abcast     -----> Module:handle_cast/2

  -               -----> Module:handle_info/2

  -               -----> Module:terminate/2

  -               -----> Module:code_change/3

  如果一個回調函數失敗或返回一個錯誤的值,gen_server將會終止。

  gen_server處理系統消息,它們記錄在sys。sys模塊可以用來調試gen_server。

  請注意,gen_server並不自動地捕獲退出信號,這個必須明確地在回調模塊啟動。

  除非另作說明,如果指定的gen_server不存在或給出錯誤參數,該模塊所有函數會失敗。

  如果一個回調函數指定"hibernate"而不是超時值,該gen_server進程會進入休眠。這也許是有用的,如果服務器預計閑置很長一段時間。不過這個功能應該小心使用,使用休眠意味着至少有兩個垃圾收集(休眠又很快喚醒),不是你想做的事情之間,每次調用一個繁忙的服務器。

導出

start_link(Module, Args, Options) -> Result
start_link(ServerName, Module, Args, Options) -> Result
  Types:
    ServerName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}
      Name = atom()
      GlobalName = ViaName = term()
    Module = atom()
    Args = term()
    Options = [Option]
      Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}
      Dbgs = [Dbg]
        Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}
      SOpts = [term()]
    Result = {ok,Pid} | ignore | {error,Error}
      Pid = pid()
      Error = {already_started,Pid} | term()

  創建一個gen_server進程作為監控樹的一部分。函數應該直接或間接地被supervisor調用。它將確保gen_server在其它方面被鏈接到supervisor。

  gen_server進程調用Module:init/1進行初始化。為確保同步啟動過程,start_link/3,4直到Module:init/1執行完成才能返回。

  如果ServerName={local,Name},gen_server使用register/2被注冊為本地的Name。如果ServerName={global,GlobalName},gen_server使用global:register_name/2被注冊為全局的GlobalName。如果沒有提供Name,gen_server不會被注冊。如果ServerName={via,Module,ViaName},gen_server將會用Module代表的注冊表注冊。Module回調應該導出函數register_name/2, unregister_name/1, whereis_name/1 和 send/2,它們表現得像global模塊對應的函數。因此,{via,global,GlobalName}是一個有效地引用。

  Module是回調模塊的名稱。

  Args是任意term,作為參數傳遞給Module:init/1。

  如果選項是{timeout,Time},gen_server被允許花費Time毫秒初始化,或者它將被終止,並且啟動函數返回{error,timeout}。
  如果選項是{debug,Dbgs},對於Dbgs里的每個條目,對應的sys函數將會被調用。參見sys。
  如果選項是{spawn_opt,SOpts},SOpts將被作為選項列表傳遞給spawn_opt內建函數,它被用來產生gen_server。

  如果gen_server被成功創建和初始化,函數返回{ok,Pid},其中Pid是gen_server的進程號。如果已經存在使用指定ServerName的進程,函數返回{error,{already_started,Pid}},其中,Pid是那個進程的進程號。

  如果Module:init因為Reason失敗,函數返回{error,Reason}。如果Module:init/1返回{stop,Reason} 或 ignore,進程被終止並且函數會分別返回{error,Reason} 或 ignore。

start(Module, Args, Options) -> Result
start(ServerName, Module, Args, Options) -> Result
  Types:
    同 start_link/3,4。

  創建一個獨立的gen_server進程,也就是,gen_server不是監控樹的一部分並且沒有監控進程。

  參看start_link/3,4了解參數和返回值的描述。

call(ServerRef, Request) -> Reply
call(ServerRef, Request, Timeout) -> Reply
  Types:
    ServerRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
      Node = atom()
      GlobalName = ViaName = term()
    Request = term()
    Timeout = int()>0 | infinity
    Reply = term()

  通過發送請求向引用名為ServerRef的gen_server進行同步調用,直到回復到達或發生超時。gen_server將調用Module:handle_call/3處理請求。

  ServerRef可以是:

  • 進程號;
  • Name,gen_server被本地注冊的名稱;
  • {Name,Node},gen_server在其它節點被本地注冊;
  • {global,GlobalName},gen_server被全局注冊;
  • {via,Module,ViaName},gen_server通過替代的進程注冊表注冊;

  Request是一個任意term,它作為其中的參數傳遞給Module:handle_call/3。

  Timeout是一個大於零的整數,它指定多少毫秒等待每個回復,原子infinity會無限期的等待。默認值是5000。如果在指定時間內沒有收到回復,函數會調用失敗。如果調用者捕獲失敗並且繼續運行,服務器僅僅晚些回復,它將在任何時候到達隨后進入調用者的消息隊列。對此,調用者必須准備這種情況,並且不保存任何垃圾消息,它們是兩個元素元組作為第一個元素。

  返回值Reply被定義在Module:handle_call/3的返回值里。

  調用可能會因為幾種原因失敗,包括超時和在調用前和調用過程中gen_server死掉。

  在調用期間當連接到客戶端,如果服務器死掉,有時會消耗退出消息,這個過時的行為已經在OTP R12B/Erlang 5.6中移除。

multi_call(Name, Request) -> Result
multi_call(Nodes, Name, Request) -> Result
multi_call(Nodes, Name, Request, Timeout) -> Result
  Types:
    Nodes = [Node]
      Node = atom()
    Name = atom()
    Request = term()
    Timeout = int()>=0 | infinity
    Result = {Replies,BadNodes}
      Replies = [{Node,Reply}]
        Reply = term()
      BadNodes = [Node]

  對所有在指定節點上被本地注冊為Name的gen_server進行同步調用,通過第一次發送請求到每個節點,然后等待回復。這些gen_server進程將會調用Module:handle_call/3處理請求。

  函數返回元組{Replies,BadNodes},其中,Replies是{Node,Reply}的列表,BadNodes是不存在節點的列表,或gen_server Name不存在或沒有回復。

  Nodes是請求被發送到的節點名稱列表。默認值是中所有已知的節點列表[node()|nodes()]。

  Name是每個gen_server被本地注冊的名稱。

  Request是一個任意term,它作為其中的參數傳遞給Module:handle_call/3。

  Timeout是一個大於零的整數,它指定多少毫秒等待每個回復,原子infinity會無限期的等待。默認值是infinity。如果在指定時間內節點沒有收到回復,該節點被加入到BadNodes。
當在節點Node來自gen_server回復Reply到達,{Node,Reply}被加入到Replies。Reply被定義在Module:handle_call/3的返回值里。

  為避免隨后的應答(在超時之后)污染調用者的消息隊列,一個中間人進程被用來做實際的調用。當它們到達一個終止的進程,遲到的回復將不會被保存。

cast(ServerRef, Request) -> ok
  Types:
  ServerRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
    Node = atom()
    GlobalName = ViaName = term()
  Request = term()

  發送一個異步請求到引用名ServerRef的gen_server,然后立即返回ok,如果目標節點或gen_server不存在,忽略消息。gen_server將調用Module:handle_cast/2處理請求。

  參看call/2,3,了解ServerRef的描述。

  Request是一個任意term,它作為其中的參數傳遞給Module_cast/2。

abcast(Name, Request) -> abcast
abcast(Nodes, Name, Request) -> abcast
  Types:
    Nodes = [Node]
      Node = atom()
    Name = atom()
    Request = term()

  發送一個異步請求給在指定節點被本地注冊為Name的gen_server。函數立即返回並且忽略不存在的節點,或gen_server Name不存在。gen_server將調用Module:handle_cast/2處理請求。

  參看 multi_call/2,3,4,了解參數描述。

reply(Client, Reply) -> Result
  Types:
    Reply = term()
    Result = term()

  當回復沒有定義在Module:handle_call/3的返回值里,該函數可以被gen_server用來顯式地發送回復給一個調用 call/2,3 或 multi_call/2,3,4的客戶端。

  Client必須是提供給回調函數的From參數。Reply是一個任意term,它將作為call/2,3 或 multi_call/2,3,4的返回值被回復到客戶端。

  返回Result沒有被進一步定義,並且應該總是被忽略。

enter_loop(Module, Options, State)
enter_loop(Module, Options, State, ServerName)
enter_loop(Module, Options, State, Timeout)
enter_loop(Module, Options, State, ServerName, Timeout)
  Types:
    Module = atom()
    Options = [Option]
      Option = {debug,Dbgs}
        Dbgs = [Dbg]
          Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}
    State = term()
    ServerName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}
      Name = atom()
      GlobalName = ViaName = term()
    Timeout = int() | infinity

  使一個已存在的進程進入一個gen_server。不返回,反而這個調用進程將進入gen_server的接收循環,並成為一個gen_server進程。這個進程必須使用proc_lib的啟動函數被啟動。用戶為該進程的任何初始化負責,包括為它注冊一個名字。

  這個函數非常有用,當需要一個更加復雜的初始化過程,而不是gen_server行為提供的。

  Module,Option 和ServerName與調用gen_server:start[_link]/3,4有着相同的含義。然而,如果ServerName被指定,進程必須在該函數被調用前相應地被注冊。

  State和Timeout與Module:init/1的返回值有着相同的含義。回調模塊Module也不需要導出一個init/1函數。

  失敗:如果調用進程未被一個proc_lib函數啟動,或者如果它未依據ServerName注冊。

回調函數

Module:init(Args) -> Result
  Types:
    Args = term()
    Result = {ok,State} | {ok,State,Timeout} | {ok,State,hibernate} | {stop,Reason} | ignore
      State = term()
      Timeout = int()>=0 | infinity
      Reason = term()

  無論何時一個gen_server使用gen_server:start/3,4 或 gen_server:start_link/3,4被啟動,該函數被一個新進程調用去初始化。

  Args是提供給啟動函數的參數。

  如果初始化成功,函數應該返回{ok,State}, {ok,State,Timeout} 或 {ok,State,hibernate},其中,State是gen_server的內部狀態。

  如果一個整數超時值被提供,一個超時將發生,除非在Timeout毫秒內收到一個請求或消息。一個超時被timeout原子標識,它應該被handle_info/2回調函數處理。infinity可以被用來無限期地等待,這是默認值。

  如果hibernate被指定而不是一個超時值,進程將進入休眠當等待下一條消息到達時(調用proc_lib:hibernate/3)。

  如果在初始化期間出現錯誤,函數返回{stop,Reason},其中,Reason是任何term,或ignore。

Module:handle_call(Request, From, State) -> Result
  Types:
    Request = term()
    From = {pid(),Tag}
    State = term()
    Result = {reply,Reply,NewState} | {reply,Reply,NewState,Timeout} | {reply,Reply,NewState,hibernate}
      | {noreply,NewState} | {noreply,NewState,Timeout} | {noreply,NewState,hibernate}
      | {stop,Reason,Reply,NewState} | {stop,Reason,NewState}
      Reply = term()
      NewState = term()
      Timeout = int()>=0 | infinity
      Reason = term()

  無論何時使用gen_server:call/2,3 或 gen_server:multi_call/2,3,4,gen_server接收請求發送,該函數被調用處理請求。


  Request是提供給call或multi_call的參數。

  From是一個元組{Pid,Tag},其中,Pid是客戶端的進程號,Tag是一個唯一標志。

  State是gen_server的內部狀態。

  如果函數返回{reply,Reply,NewState}, {reply,Reply,NewState,Timeout} 或 {reply,Reply,NewState,hibernate},Reply將被回復給From作為call/2,3 或 multi_call/2,3,4的返回值。然后gen_server繼續執行,可能更新內部狀態NewState。參看Module:init/1了解Timeout和hibernate的描述。

  如果函數返回{noreply,NewState}, {noreply,NewState,Timeout} 或 {noreply,NewState,hibernate},gen_server將用NewState繼續執行。任何對From的回復必須顯式使用gen_server:reply/2。

  如果函數返回{stop,Reason,Reply,NewState},Reply將回復給From。如果函數返回{stop,Reason,NewState},任何對From的回復必須顯式使用gen_server:reply/2。然后,函數將調用Module:terminate(Reason,NewState),隨后終止。

Module:handle_cast(Request, State) -> Result
  Types:
    Request = term()
    State = term()
    Result = {noreply,NewState} | {noreply,NewState,Timeout} | {noreply,NewState,hibernate} | {stop,Reason,NewState}
      NewState = term()
      Timeout = int()>=0 | infinity
      Reason = term()

  無論何時,gen_server接收一個請求發送使用gen_server:cast/2 或 gen_server:abcast/2,3,該函數被調用處理請求。

  參見Module:handle_call/3了解參數和可能返回值的描述。

Module:handle_info(Info, State) -> Result
  Types:
    Info = timeout | term()
    State = term()
    Result = {noreply,NewState} | {noreply,NewState,Timeout} | {noreply,NewState,hibernate} | {stop,Reason,NewState}
      NewState = term()
      Timeout = int()>=0 | infinity
      Reason = normal | term()

  該函數被gen_server調用,當超時發生或接收到其它消息而不是同步或異步請求(或者系統消息)。

  Info是原子timeout,當超時發生,或是已接收的消息。

Module:terminate(Reason, State)
  Types:
    Reason = normal | shutdown | {shutdown,term()} | term()
    State = term()    

  該函數被gen_server調用,當它准備終止。它應該和Module:init/1相反,並做必要的清理。當它返回時,gen_server由於Reason終止。返回值被忽略。

  Reason是一個term,指出停止原因,State是gen_server的內部狀態。

  Reason取決於gen_server終止的原因。如果因為另一個回調函數已經返回一個停止元組{stop,..},Reason將會有指定的值在那個元組。如果是由於失敗,Reason是錯誤原因。

  如果gen_server是監控樹的一部分,並且被監控者有序終止,該函數將被調用,使用Reason=shutdown,如果應用以下狀態:

  • gen_server已經設置為退出信號;
  • 並且,被定義在監控者的子規范的關閉策略是一個整數值,而不是brutal_kill。

  即使gen_server不是監控者的一部分,如果收到來自父進程的'EXIT'消息,函數將被調用。Reason將和'EXIT'消息一樣。

  否則,gen_server將立即終止。

  注意,除了normal,shutdown,或{shutdown,Term}的其他原因,gen_server被設定終止由於一個錯誤,並且使用error_logger:format/2報告一個錯誤。

Module:code_change(OldVsn, State, Extra) -> {ok, NewState} | {error, Reason}
  Types:
    OldVsn = Vsn | {down, Vsn}
      Vsn = term()
    State = NewState = term()
    Extra = term()
    Reason = term()

  該函數被gen_server調用,當它在版本升級/降級應該更新自己的內部狀態,也就是說,當指令{update,Module,Change,...}在appup文件中被給出,其中Change={advanced,Extra}。參看OTP設計原則查看更多信息。

  在升級的情況下,OldVsn就是Vsn;在降級的情況下,OldVsn就是{down,Vsn}。Vsn被回調模塊Module的老版本的vsn屬性定義。如果沒有這樣的屬性定義,版本就是BEAM文件的校驗和。

  State是gen_server的內部狀態。

  Extra來自升級指令的{advanced,Extra}部分,被原樣傳遞。

  如果成功,函數應該返回被更新的內部狀態。

  如果函數返回{error,Reason},正在進行的升級將會失敗,並且回滾到老版本。

Module:format_status(Opt, [PDict, State]) -> Status
  Types:
    Opt = normal | terminate
    PDict = [{Key, Value}]
    State = term()
    Status = term()

  請注意,該回調可選,所以回調模塊不需要導出它,這個回調模塊提供一個默認實現,該函數返回回調模塊狀態。

  該函數被gen_server進程調用:

  • sys:get_status/1,2被調用獲取gen_server狀態。這種情況,Opt被設置成normal。
  • gem_server異常終止,生成錯誤日志。這種情況,Opt被設置成terminate。


  該函數是有用的,對於這些情況定制gen_server的格式和表現。一個回調模塊希望定制sys:get_status/1,2的返回值,和它在終止錯誤日志的狀態表現,導出一個format_status/2實例,返回描述gen_server當前狀態的term。

  PDict是gen_server的進程字典的當前值。

  State是gen_server的內部狀態。

  函數應該返回Status,定制當前狀態的細節和gen_server的狀態的term。在Status格式上沒有任何限制,但是對於sys:get_status/1,2情況,對於Status建議的格式是[{data, [{"State", Term}]}],其中,Term提供gen_server相關的細節。遵循這些建議不是必須的,但是這樣做將使回調模塊的狀態與sys:get_status/1,2的返回值一致。

  該函數的一個用法是返回緊湊的替換狀態表示來避免有過大的狀態項打印在日志里。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM