zoukankan      html  css  js  c++  java
  • 终端里面的程序是怎样跑起来的

      比如mac环境下在某个路径下面跑celery的任务,celery -A msg_task worker 对于这一段语句的理解其实就是用后面的这些参数跑起来celery的可执行文件;那具体是怎样跑起来的呢,分为如下的四个步骤。

    一:mac的环境变量
      mac 一般使用bash作为默认shell,Mac系统的环境变量,加载顺序为:
      Ⅰ.(系统级别,系统启动就会加载)
        /etc/profile /etc/paths
      Ⅱ.(当前用户级的环境变量,因为~文件夹本身就是登录人的home目录,根据shell的不同,加载的配置文件可能不一样,比如如果用的是zsh的话,那这边的第一个文件就会是~/.zshrc;然后如果其中的~/.bash_profile文件存在,后面的文件就会忽略不读,如果不存在,才会读后面的文件)
        ~/.bash_profile ~/.bash_login ~/.profile
      Ⅲ.(bash shell打开的时候载入的)
        ~/.bashrc
      比如我的电脑上面看见/etc/path文件里面的内容是
        /usr/local/bin
        /usr/bin
        /bin
        /usr/sbin
        /sbin
      然后在~/.zprofile的内容是PATH="/Library/Frameworks/Python.framework/Versions/3.4/bin:${PATH}"
      最后在~/.zshrc的内容是export PATH=/usr/local/sbin:$HOME/bin:/usr/local/bin:$PATH
      所以最后我们在终端里面打印环境变量PATH,使用echo $PATH 得到的信息是/usr/local/sbin:/Users/sunmenghua/bin:/usr/local/bin:/Library/Frameworks/Python.framework/Versions/3.4/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin,这就对应上了

    二:找到可执行文件
      在/usr/local/bin【路径1】和/Library/Frameworks/Python.framework/Versions/3.4/bin【路径2】路径下面,我们都发现了celery
      然而执行celery -A msg_task worker的时候,发现,执行有报错,说【路径1】下面的celery是一个错误的编译器(bad interpreter),并且/usr/ocal/opt/python3/bin/python3.5不存在,所以在【路径2】找到对应的可执行文件

    三:分析可执行文件

      打开文件,能够定位到入口是在celery模块中__main__.py里面的面函数,看到的内容是: 

    1 import re
    2 import sys
    3 from celery.__main__ import main
    4 if __name__ == '__main__':
    5   sys.argv[0] = re.sub(r'(-script.pyw|.exe)?$', '', sys.argv[0]) # 正则匹配与替换
    6   sys.exit(main())    # 退出时运行从celery模块的__main__.py里面的main函数

      篇外话:发现了一个比较有用处的模块,就是sys模块。之前我写脚本的时候,都是使用的tornado.options模块。使用形式是:  

    1 from tornado.options import options, define # 引入模块
    2 define("action", default="userinc", help="update static module") # 定义传进来的参数
    3 if __name__ == "__main__":
    4 options.parse_command_line() # 分析命令行里面传进来的所有参数,默认是sys.argv,然后会丢掉第一个参数sys.argv[0],因为它是程序名
    5 action=options.action    然后调用形式就是 python3 test.py --action=test,经过追踪tornado的源码,知道这个模块其实是在sys.args进行了一层封装
    四:找到python3模块  
    通过import celery ,然后help(celery),  
    Ⅰ.找到模块的源码所在地方为/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/celery/;  

    Ⅱ.用sublime打开对应的文件夹,先找__main__.py,在根据导入模块找到celery/bin/celery.py里面的main函数
    Ⅲ.找到执行方法是在class CeleryCommand的execute_from_commandline;
    Ⅳ.继续向上追溯,执行方法在celery.bin.base里面的execute_from_commandline;
    Ⅴ.打印调试,真正读参数是在setup_app_from_command(argv)
    Ⅵ.打印调试,往下走到self.find_app(app);
    Ⅶ.调用的是from celery.app.utils import find_app方法传给他的两个参数,一个app是上面传下来的参数,另一个是symbol_by_name,这个参数是一个函数,搞得非常复杂,简直太复杂了,绕的一大圈。
    ###这里尝试描述一下:
    ##A.find_app(app, symbol_by_name=self.symbol_by_name)使用的是当前类里面的函数;
    ##B.from celery.utils import imports
    ##def symbol_by_name(self, name, imp=imports.import_from_cwd):
    ##return imports.symbol_by_name(name, imp=imp)
    ##C0.但是在celery/utils.py里面又有from celery.utils.imports import import_from_cwd,symbol_by_name
    ##D0.继续去celery/utils/imports.py里面又发现:from kombu.utils.imports import symbol_by_name
    ##E0.找kombu/utils/imports.py,确实是最后的导入是在这边,可是这里的逻辑是如果没有传导入函数的话,那就用importlib.import_module做导入函数,否则用调用的时候传的导入函数;好吧,那我们使用的时候,其实在步骤B里面有传入一个导入函数,那我们就继续追着B看一下,这个导入函数是哪里传入进来的;
    ##C1:跟C0一样
    ##D1:像B的这种形式,那是没有传参数的,所以,这边得到的这个函数也是importlib.import_module

    上面的追踪不继续描述了,言语难以表达。
    不过在追踪的过程中,还是有几点理解。
      1.函数不调用就不执行。
        写一个简化的调用。

    def t1():
     print('t1')
    
    def main(c=t1):
     c()
     print('main')
    
    if __name__ == '__main__':
        main()
    def t1():
     print('t1')
    
    def main(c=t1):
     print('main')
    
    if __name__ == '__main__':
        main()

     


        

        第一个的打印是t1和main,第二个的打印是main
      2.后面跟别人聊,本来我以为这样子的代码应该算是一种比较糟糕的代码;但是被告知,这种难以理解代码的产生是面向对象编程和产品迭代产生的;调用某个新的模块的时候,不需要知道他的内部实现原理,只需要他的参数和返回,然后如果想拓展他,就直接拓展接口就好了。

    但我还是不太理解,后面再想想吧。

  • 相关阅读:
    LeetCode 382. Linked List Random Node
    LeetCode 398. Random Pick Index
    LeetCode 1002. Find Common Characters
    LeetCode 498. Diagonal Traverse
    LeetCode 825. Friends Of Appropriate Ages
    LeetCode 824. Goat Latin
    LeetCode 896. Monotonic Array
    LeetCode 987. Vertical Order Traversal of a Binary Tree
    LeetCode 689. Maximum Sum of 3 Non-Overlapping Subarrays
    LeetCode 636. Exclusive Time of Functions
  • 原文地址:https://www.cnblogs.com/summery91/p/6209550.html
Copyright © 2011-2022 走看看