Linux使用ragel进行文本快速解析(下)
1、前言
《Linux使用ragel进行文本快速解析(上)》文中对Ragel进行了初步介绍,并给出了一个atoi的例子,本文接着再给出一个文本行解析的例子
2、思路
awk的主要是对固定列数的文本进行内容解析,若使用 awk命令的话,是进行逐行解析。同样的,使用 Ragel 写的思路也是,编写正则以行为单位,进行读取解析。但是相比命令的方式,Ragel 相当于可编程处理,则能灵活地对不固定行的文本进行处理。
3、源码
代码的实现在ragel-6.10/examples/awkemu.rl
先看状态机这块的代码:
%%{machine awkemu;action start_word {ws[nwords] = fpc;} action end_word {we[nwords++] = fpc;} action start_line {nwords = 0;ls = fpc;} action end_line {printf("endline(%i): ", nwords );fwrite( ls, 1, p - ls, stdout );printf("\n");for ( i = 0; i < nwords; i++ ) { printf(" word: ");fwrite( ws[i], 1, we[i] - ws[i], stdout );printf("\n");} } # Words in a line.word = ^[ \t\n]+;# The whitespace separating words in a line.whitespace = [ \t];# The components in a line to break up. Either a word or a single char of# whitespace. On the word capture characters.blineElements = word >start_word %end_word | whitespace;# Star the break line elements. Just be careful to decrement the leaving# priority as we don't want multiple character identifiers to be treated as# multiple single char identifiers.line = ( blineElements** '\n' ) >start_line @end_line;# Any number of lines.main := line*;
}%%%% write data noerror nofinal;
可以看出,行由多个元素组成: line = ( blineElements** ‘\n’ ) >start_line @end_line;
元素由单词、分隔符进行区分: blineElements = word >start_word %end_word | whitespace;
代码中获取字符串的动作并没有进行内存拷贝,而是通过暂存字符串指针到数组 ws we 保存。
再看一下主函数的入口:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define MAXWORDS 256
#define BUFSIZE 4096
char buf[BUFSIZE];int main()
{int i, nwords = 0;char *ls = 0;char *ws[MAXWORDS];char *we[MAXWORDS];int cs;int have = 0;%% write init;while ( 1 ) {char *p, *pe, *data = buf + have;int len, space = BUFSIZE - have;/* fprintf( stderr, "space: %i\n", space ); */if ( space == 0 ) {fprintf(stderr, "buffer out of space\n");exit(1);}len = fread( data, 1, space, stdin );/* fprintf( stderr, "len: %i\n", len ); */if ( len == 0 )break;/* Find the last newline by searching backwards. This is where* we will stop processing on this iteration. */p = buf;pe = buf + have + len - 1;while ( *pe != '\n' && pe >= buf )pe--;pe += 1;/* fprintf( stderr, "running on: %i\n", pe - p ); */%% write exec;/* How much is still in the buffer. */have = data + len - pe;if ( have > 0 )memmove( buf, pe, have );/* fprintf(stderr, "have: %i\n", have ); */if ( len < space )break;}if ( have > 0 )fprintf(stderr, "input not newline terminated\n");return 0;
}
主函数是读取文件内容,通过调用 %% write exec; 将内容传到状态机中进行解析,
开始一看还是挺复杂的,为啥不考虑通过 fgets读取一行进行处理?所以又进行修改试验。
int ragel_awkemu(const char *str)
{const char *p = str, *pe = str + strlen(str);int cs; int i, nwords;const char *ls = NULL;const char *ws[MAXWORDS] = {NULL};const char *we[MAXWORDS] = {NULL};/* Initialize and execute. */%% write init;%% write exec;return nwords;
}int main(int argc, char *argv[])
{char buf[SIZE_LINE_NORMAL];while (fgets(buf, sizeof(buf), stdin) != 0) {int value = ragel_awkemu(buf);printf("num: %d\n", value);} return 0;
}
4、运行
首先简单地测试,两种方法都能进行文本解析。为了压测两种方法的真正能力,造了100w行的日志信息到文件里,一行15列数据,总文件大小为300MB。
原版,按块取:
centos-x64 [ ~ ]# time ./awkemu < /tmp/syslog.dat >/dev/null
real 0m2.581s
user 0m2.484s
sys 0m0.094s
修改版,按行取:
centos-x64 [ ~ ]# time ./awkemu2 < /tmp/syslog.dat >/dev/null
real 0m3.488s
user 0m3.372s
sys 0m0.111s
性能方面,速度达到30~40w/s的速度。同时,可以看出行解析稍微慢了一些,但是通过strace查看时,不管fgets还是fread底层都是调用read接口,所以开销的区别并不在接口调用次数上。
再仔细阅读对比一下main函数,最后分析开销的区别是再调用次数方面,还是fread以每次处理的数据多、调用次数少占优。每次读到(拷贝)一块大buffer,再通过状态机进行逐个字符解析。若碰巧最后几个字符不足整行的话,memmove 到buffer头进行下一次处理。
5、结论
Ragel提供了一个经典的awk例子,同时也告诉我们,通过尽可能的块数据获取减少函数调用,尽可能减少内存拷贝,这样才能把性能发货到极致。
Linux使用ragel进行文本快速解析(下)相关推荐
- Linux内核很吊之 module_init解析 (下)【转】
转自:https://blog.csdn.net/richard_liujh/article/details/46758073 版权声明:本文为博主原创文章,未经博主允许不得转载. https://b ...
- Linux内核很吊之 module_init解析 (下)
Linux内核很吊之 module_init解析 (下) 转载 2017年01月23日 13:58:21 标签: 95 编辑 删除 转自: http://blog.csdn.net/richard_l ...
- Linux用一键安装包快速部署禅道项目管理平台
Linux用一键安装包快速部署禅道项目管理平台 简介:本文介绍如何在linux下面使用禅道一键安装包搭建禅道的运行环境. 一.安装 二.如何访问数据库 三.9.2.stable版本起Linux一键安装 ...
- linux软件包管理解析,linux学习笔记_09_软件包管理解析.doc
linux学习笔记_09_软件包管理解析 软件包管理 软件包分类 源码包(C语言编写的源代码) linux主要由C语言来写. 源码包可以用写字板打开 脚本安装包:源码包进行再开发的源码包(提供安装界面 ...
- java csv快速解析_爸爸解析:闪电般的快速CSV解析体验
java csv快速解析 总览 (Overview) With a plethora of options to parse CSV files/data and adding to it the i ...
- Linux中的简单文本处理
文本处理命令 tr命令(可以用来删除一段文本信息中的某些文字,或者将其进行转换) 格式: tr [option] - SET1 [SET2] 可选参数: -d: 删除和set1匹配的字符 -s:去除s ...
- 如何浏览文本字段(下一个/完成按钮)
如何使用iPhone键盘上的"下一步"按钮浏览所有文本字段? 最后一个文本字段应该关闭键盘. 我已经设置了IB按钮(下一个/完成),但现在我被卡住了. 我实现了textFieldS ...
- 手把手教你用 TensorFlow 实现文本分类(下)
手把手教你用 TensorFlow 实现文本分类(下) 本文作者:AI研习社 2017-05-29 13:36 导语:文本分类全流程解析. 雷锋网(公众号:雷锋网)按:本文作者张庆恒,原文载于作者个人 ...
- linux sort 时间排序,linux sort多字段排序实例解析
本文研究的主要是linux sort多字段排序,具体介绍如下. Linux多数发行版自带的sort程序,非常强大,在此只说多字段排序 sort 有个参数-k,可以指定字段,有比较复杂的语法,不在文本范 ...
- linux编辑文档windows,1.9vim编辑器linux内核的底层文本编辑器,跟windows系统上的文本文档类似,大部分用这个工具进行文本的编辑,这个工具的操作方式基本上用不到鼠标,多是...
1.9vim编辑器 linux内核的底层文本编辑器,跟windows系统上的文本文档类似,大部分用这个工具进行文本的编辑,这个工具的操作方式基本上用不到鼠标,多是用命令去操作 这个工具分为三种模式:命 ...
最新文章
- 标题与文字的组合[摘]
- Boost:fork联接的测试程序
- 10如何成为卓越领导者摘录——卓越的领导者
- 飞秋(FeiQ)2012版择日发布
- python--二叉树库函数
- github上创建java项目简单操作
- 中年男人的唯一出路就是安分守己
- Log4j2 Zero Day 漏洞 Apache Flink 应对指南
- .bin文件如何打开并使用
- Android Studio User Manual
- 测试人员在工作中如何查日志?
- EagleEye的特性分析
- 聚合数据API接口调用方法
- seo关键词优化的技巧
- 畅想未来计算机和人工智能的应用,人工智能在生活中的应用及展望
- 帝国cms小程序端源码
- r语言中的或怎么表示什么不同_R语言中$是什么意思
- Zxing和QR CODE 生成与解析二维码实例(普通篇)
- R语言大数据分析纽约市的311万条投诉统计可视化与时间序列分析
- matlab之请求用户输入函数input