感谢各位的认可,读源代码的过程很艰难,谢谢大家让我有了继续阅读的动力!
正在看pandas的源代码,相信我的回答能给问主一定的帮助,现在只看了读文件的过程,之后在阅读源码的过程中会不断更新。
首先,看下从pandas.read_csv(filename, kwds)的整个调用过程(这里参数先略去,虽然有些参数很重要),如图所示,用到了1个重要的类,TextReader类,这个类是负责文件读写,核心的加速都在这里,可以看到这个类是用Cython+C写的,然后被编译成parser.pyd文件,用C进行文件读写,因此速度非常快,在读大文件时会比python快很多倍,之后会详细得看这个TextReader类。
对TextReader类进行调用分析(无法调试,只能一行一行看,看起来很艰难),整个调用过程,如图所示,用到了1个类TextReader,这个类负责整个读写过程的调度和获得数据后的处理,用cython编写。还有1个结构体parser_t,这个结构体中存储了文件指针、数据以及对数据分析后的一些变量,在图中已详细介绍这些变量的用途。
整个过程大致是,TextReader创建结构体parser_t的实例parser,用parser打开文件(io.c中),用parser读入数据(io.c中),对数据进行分析并设置单词指针和行指针(tokenize.c),注意,对数据分析的过程是一个有限状态机,之后会详细的看这个过程。
------------------------------------ 2017/05/01更新------------------------------------
源代码中的有限状态机比较复杂,精简后的核心部分如下图。
初始状态为“开始记录”(START_RECORD)。
状态为“开始记录”(START_RECORD),如果读到正常字符,状态变为“开始域”(START_FIELD);如果读到结束符,调用end_line函数,对line_start数组进行更新。
状态为“开始域”(START_FIELD),如果读到正常字符,状态变为“域内”(IN_FIELD),调用push_char函数,对stream数组加1。
状态为“域内”(IN_FIELD),如果读到正常字符,状态变为“域内”(IN_FIELD),调用push_char函数,对stream数组加1;如果读到分隔符(如 ),状态变为“开始域”(START_FIELD),调用end_field函数,更新pword_start和words数组,并且将line_field加1;如果读到结束符(如 ),状态变为“开始记录”(START_RECORD),并调用end_field和end_line函数。
经过上述的有限状态机进行数据处理之后,便能得到stream, words, pword_starts, line_start, line_fields这些重要的数组(上文已经一一介绍)。