• erlang判断模块导出函数问题


    erlang本身提供一个接口,可以用来检查模块是否有导出函数,这个接口是erlang:function_exported/3,但是很多时候这个接口无法正常使用。
    下面重现一下这个问题:
    [plain] view plaincopy
     
    1. 1> erlang:function_exported(crypto,start,0).  
    2. false  
    3. 2> crypto:start().  
    4. ok  
    5. 3> erlang:function_exported(crypto,start,0).  
    6. true  
    注意:例子中并不是说一定要crypto:start()才能使用这个函数,只是说这个函数确实存在。
     
    现在,来看下erlang对这个接口的说明:
    Returns true if the module Module is loaded and contains an exported function Function/Arity; otherwise false.
    Returns false for any BIF (functions implemented in C rather than in Erlang).
    换句话说,如果一个模块还没有被加载,就无法使用erlang:function_exported/3函数。很多模块在erlang启动时都没有加载到系统,都是在使用到的时候才加载,所以这个检查导出函数的接口可能会出现错误的结果。
     
    如果要判断模块是否有导出函数,那么,我们可以像下面这么写,就可以正常使用了。
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. -module(test).  
    2. -compile(export_all).  
    3.   
    4. function_exported(Module, Function, Arity) ->  
    5.     case erlang:module_loaded(Module) of  
    6.         true ->  
    7.             next;  
    8.         _ ->  
    9.              code:ensure_loaded(Module)  
    10.     end,  
    11.     erlang:function_exported(Module, Function, Arity).  
    另外,如果模块被改成bif也无法判断了。不过这倒不用太过担心,我们自己写的函数都不会是bif

    最后,讨论下erlang:function_exported/3为何只能检查已加载过的模块?
    为了实现热更新,新旧代码替换,erlang维护了一个全局哈希表,用于描述模块导出函数信息。那么,只要加载过的模块就会被记录信息到这个哈希表,保存这些信息也要耗费一定的内存开销,而且,哈希算法本身存在冲突的可能性,元素越多,发生冲突的可能性越大,为了解决冲突,还会引入了bucket(哈希桶)或者链表。这样,如果要保证键值分散,就会浪费很多空间,不然又会影响查找效率。
    所以,erlang只记录了加载过的模块信息,其他等到使用到的时候再加载。
    erlang:function_exported/3是一个bif函数,实现函数可以在ertsemulatoreamif.c找到:
    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. BIF_RETTYPE function_exported_3(BIF_ALIST_3)  
    2. {  
    3.     if (is_not_atom(BIF_ARG_1) || is_not_atom(BIF_ARG_2) ||  is_not_small(BIF_ARG_3)) {  
    4.         BIF_ERROR(BIF_P, BADARG);  
    5.     }  
    6.     if (erts_find_function(BIF_ARG_1, BIF_ARG_2, signed_val(BIF_ARG_3),   
    7.             erts_active_code_ix()) == NULL) {  
    8.         BIF_RET(am_false);  
    9.     }  
    10.     BIF_RET(am_true);  
    11. }  
    erts_find_function实现在ertsemulatoreamexport.c中:
    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /* 
    2.  * Find the export entry for a loaded function. 
    3.  * Returns a NULL pointer if the given function is not loaded, or 
    4.  * a pointer to the export entry. 
    5.  * 
    6.  * Note: This function never returns export entries for BIFs 
    7.  * or functions which are not yet loaded.  This makes it suitable 
    8.  * for use by the erlang:function_exported/3 BIF or whenever you 
    9.  * cannot depend on the error_handler. 
    10.  */  
    11.   
    12. Export* erts_find_function(Eterm m, Eterm f, unsigned int a, ErtsCodeIndex code_ix)  
    13. {  
    14.     struct export_templ templ;  
    15.     struct export_entry* ee;  
    16.   
    17.     ee = hash_get(&export_tables[code_ix].htable, init_template(&templ, m, f, a));  
    18.     if (ee == NULL ||   (ee->ep->addressv[code_ix] == ee->ep->code+3 &&  
    19.      ee->ep->code[3] != (BeamInstr) BeamOp(op_i_generic_breakpoint))) {  
    20.         return NULL;  
    21.     }  
    22.     return ee->ep;  
    23. }  
    这里,export_tables是一个全局变量,还是在export.c,其中,code_ix被用来控制代码版本,有时间的话再讨论erlang热更新机制
    [cpp] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. static IndexTable export_tables[ERTS_NUM_CODE_IX];  /* Active not locked */  
    所以,erlang:function_exported/3只是去查找导出函数的哈希表,找到返回true,没有就false
     
    参考:http://blog.csdn.net/mycwq/article/details/40663737
  • 相关阅读:
    fiddler 使用
    IO多路复用
    scrapy下载 大文件处理

    session见解
    自定义分页
    COOKIE
    ORM之老师管理
    ORM之学生管理
    ORM之班级管理
  • 原文地址:https://www.cnblogs.com/fvsfvs123/p/4169049.html
Copyright © 2020-2023  润新知