Archive for 算法-编程

包初始化创建我是用的rstudio,创建的r package项目。 然后可以build菜单选择build source package,右侧的build窗口可以check,install,非常快的点击就完成了 也可以用命令做 R CMD build tpk R CMD CHECK R CMD INSTALL tpk 这里我傻了吧唧,命令行操作的时候, install 后面跟了个tar包全名,导致后边用install.package时候也是用的全名,导致查错误也每个结果。搞了半天发现名字不对。

Continue

没有系统学过r的坏处体现出来了,现在想到什么就要去搜什么。 常量好像在R中是不存在的,sof上看到一个例子,但是没啥用,还不如直接注释声明。 a <- 1 lockBinding("a", globalenv()) a <- 2 Error: cannot change value of locked binding for 'a' 非包中全局变量,可以使用<<-来保证局部变量引用的全局变量,但包内的不知道。通过查找,基本实现方式一个是通过myenv <- new.env()来实现,这个返回类型为environment,还没有细看。 还有一种实现方式是使用.onLoad,在包加载的时候可以调用的一些列函数。一般声明在zzz.R文件中,这个文件名是约定俗成的。

Continue

要写项目就需要想到这些,因为没有经验,只能网上找一些项目或者搜一些规范。大部分都是package的项目,所以我找文章找到一些规范。 https://www.r-bloggers.com/2018/08/structuring-r-projects/ 这篇文章介绍比较全面,目录结构大部分按他这个来了。其中对于library(package)载入包的情况进行了说明,可以使用package::function(arg1, arg2, ...)来调用不常用包的函数,这个方式的好处是不会打乱命名空间,除非知道这些包没有冲突,不然确实出现问题不一定好排查。(提前看文章避免了坑) 还有一些代码规范,但是我应该之会借鉴一部分变量命名方式,像参数空格这种我就不准备用了。 http://stat405.had.co.nz/r-style.html 然而查了一大顿之后,我决定还是把项目组织成R语言 package的目录结构,因为那个比较规范,也有文档测试啥的目录,很清晰。 具体需要参考https://cran.r-project.org/doc/manuals/R-exts.pdf官方文档了

Continue

刚研究了log4r的使用,就想着也不是什么大包,自己也没写r项目的经验,看看源码学习一下吧。然后在appender里看file_appender的时候,看到了一个force函数。 本能的去Rstudio上查了一下文档,因为软件看文档比终端好一点。然后发现这个不简单啊。 幸好之前写过python对这种坑机制有了解,感觉上R与Python很多地方相似。 安装文档说明,R函数的参数在定义的闭包中使用的时候,比如在循环和apply函数的调用,会导致从变量作用域中获取这些参数变量,也就是所谓的惰性求值。虽然我现在看的文档中还没有涉及变量作用域的问题,感觉在R中应该和在Python中是差不多的,循环体是不具有变量作用范围的保证的。而force函数能保证这个参数被执行求值,从而保证闭包里作用域里的变量的值的变化。 ?force文档里有个例子很好的说明了这一点。

Continue

看log4r的名字就感觉跟log4j有渊源啊,其中还要好多个日志包,最后决定log4r和logging里边一个,logging是仿的python日志模块的包,但是我最后没选这个,主要是因为接口设计的不太好,就选择了log4r。 安装包 install.packages("log4r") 使用 library(log4r) logger <- logger("INFO", appenders = file_appender("log/base.log")) info(logger, "info") debug(logger, "debug") error(logger, "error") 使用的时候有几个点需要注意, 我目前安装最新的版本是 0.3.2,但是?log4r的文档版本是0.2,然后我用那个文档里的老接口和github上的新接口混用,导致日志文件没更新成功。后来才意识到文档不对。 日志文件在输出第一条日志的时候才会创建。

Continue

找了点关于python和r语言的对比文章看了看,总结了下边几条。 R 统计模型新 可视化,动态报告稍微领先 统计,数据分析,领域专用 Python 效率领先 语言稳定规范 数据清洗方便 工程开发,领域广 我刚开始学习R语言,还没有太多体会,不过从语言层面,感觉R语言的语法分析系统都不完善,不知道为啥函数参数的缺少只能运行时知道,不知道有没有别的作用。

Continue

neutron-dhcp-agent服务启动命令 /usr/bin/neutron-dhcp-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/dhcp_agent.ini 调用了neutron_service.Service.create()来创建的server。Service(n_rpc.Service)继承自neutron_lib.rpc,这次得去看看了,感觉应该也没啥看的。 Service(service.Service)继承自oslo_service.service.Service,里边只是个定义类接口,里边还有个线程池self.tg。 Service传入的manager为neutron.agent.dhcp.agent.DhcpAgentWithStateReport, 然后实例化,最后初始化父类。 DhcpAgentWithStateReport继承自DhcpAgent,再继承自manager.Manager, 然后继承自periodic_task.PeriodicTasks,看起来是个定时任务。先不细看了,按初始化流程走。 在DhcpAgent里dhcp_driver_cls存的dhcp_driver的类,文档安装使用的neutron.agent.linux.dhcp.Dnsmasq,这个先记录,后边看。DhcpPluginApi这个是定义了dhcp rpc的client端,从注释看server端在neutron.api.rpc.handlers.dhcp_rpc.DhcpRpcCallback,具体还不知道为啥这么搞,先记录。看接口内容感觉就是网络的几个常规接口。DhcpAgentWithStateReport里的初始化,也是初始化了一个心跳进行状态上报。 launch方法传入初始化完的server, 启动一个进程,restart方法mutate_config_files on SIGHUP,这个先记录。workers为1走的是ServiceLauncher,继承自Launcher,然后初始化Services,这个也有个线程池。最后初始化SignalHandler。.wait()里边看注释是等待重启服务的信号. 看了一下DhcpRpcCallback,这个看不太懂了,其中的plugin的初始化不太清楚。状态不行,不看这个了。 Dnsmasq继承自DhcpLocalProcess, 再继承自DhcpBase,初始化了一个DeviceManager是与之前的rpc调用相关的没细看。 是通过call_driver来实例化的,但是看起来都是用到的时候才初始化的,看初始化方法和调用,基本都是传入network和action然后,初始化完成后,执行action的方法,所以应该是针对不同网络进行实例化并操作。 主要逻辑都是在Dnsmasq里定义的,existing_dhcp_networks看注释是返回dhcp网络,直接从配置文件目录读取,这个也说明创建网络会在这个目录创建配置文件。_build_cmdline_callback看样子是启动dnsmasq的命令生成的地方。spawn_process启动dnsmasq的进程,调用_get_process_manager,这个是在DhcpLocalProcess, 然后还加入监控。启动是先使用external_process.ProcessManager初始化ProcessManager类,在调用enable()通过传入的cmd_callback,也就是_build_cmdline_callback那个生成cmd,启动服务进程. 随便看了一下,流程连不起来了。这里代码太绕了,不知道怎么个调用的。感觉流程最好搭个环境,打打日志比较好。 这个看的有点失败,获得了很少的东西。

Continue

linux内核使用许多likely和unlikely宏,这两个宏的内容为: #define likely(x) (__builtin_expect(!!(x), 1)) #define unlikely(x) (__builtin_expect(!!(x), 0)) 是用来告诉编译器,当前判断条件是否常用或者不常用。编译器根据提示,生成的二进制的代码流程会有相应改变,以达到让cpu尽可能的顺序执行的目的。gcc官方文档里说,使用-fprofile-arcs来进行实际的性能测试,说程序员对自己的程序的预测一般都是错误的。 然后我搜到是用gcov去做,使用了一下确实很直观。编译的时候,参数加上“-fprofile-arcs -ftest-coverage”。然后运行会生成 .gcda .gcno文件。用gcov source.c会生成相应代码的.gcov文件。vim编辑这些文件,就能看到源码形式的,每一行都执行了多少次。 这里说个疑问,前边说预测不准确,我当时看到那里还说真的是不准确。我之前就感觉明明会大概率走这个分支,然后加上提示后,速度却变慢了。但是当我用gcov去做完统计之后,发现确实很大很大概率走的那个分支,但是不知道为啥会变慢。我O2开反汇编发现内容是一样的,也可能是我测试的时候没开O2也许有不同。

Continue

想到了三种方式,但是结果跟自己预想的不太一样,具体也没有细想。 第一种方式就是char*类型的strcmp比较,这种比较容易想到。但是效率中等。 第二种方式是使用类型__uint128_t,这个是gcc给出的类型,应该可移植性不太高,这种方式速度最快,char*用的时间是差不多1.5倍。 第三种方式是使用sse,并行试试,_mm_xor_si128和_mm_test_all_zeros进行比较,但是速度是最慢的,可能涉及类型的转换,看指令也非常的多。我还以为会是最快的。 除了第三种慢的意外,我第一种还对比了第一个char就不相等的情况,这种特殊情况我以为第一种会快,没想到还是慢,跟之前速度差不多。 我特意看了一下第二种方式的实现方式:通过两个xor,分别对比8字节,然后通过or操作把两个对比结果合并,然后通过test指令判断合并的结果是否为0,test指令会修改ZF标志位,最后通过jne判断ZF标志位进行跳转。

Continue

最近看c底层相关的指令,操作,编码,多线程,磁盘文件读写相关的看的比较多。不经理永远不知道这里边的东西有多少,还有很多不易理解的。由于时间仓猝,本来想好好整理一下,作为一个总结,但还是决定只是记一个笔记,而且内容来自搜索引擎,有一部分不是看的官方文档解释等,可能不正确,而且没有写全。以后无聊的时候想起来再搞吧(感觉用不到以后不会再搞了) 先说为什么写这个文章,我碰到一个问题。多线程读写文件,然后单线程读取,线上后读取结果不一致。之前有过分步的测试,是没有问题的。 然后我排查原因,先从读入手,发现数据有问题,然后转到看写。写先通过单独打印几条日志,和对写入的数据错误判断,在某个函数。这时候,我打开编译的debug模式,就是能打印更详细的日志,然后发现问题没了,数据正常了。然后我就玩起了编译参数。发现打印日志就没事,不打印就出问题了,然后我就想到是编译器给我优化过头了,那时候还是开始02的优化。因为那个函数不涉及多线程的操作。然后我去掉 -DNDEBUG参数,然后用assert()判断出是哪一行出了问题。然后实验了几个方法,发现都是可以的,于是网上搜索资料,大体比较了一下这集中方式,选了一种。 1,把变量声明称volatile,主要功能是,编译器不会优化掉这个变量,然后变量的值不会存到寄存器,保证从内存中读取。看我的程序具体也看不出来,除非反汇编代码看看。也懒得看了。 2,__sync_synchronize (...),This builtin issues a full memory barrier. 内存栅栏,这个是个硬件栅栏,效率相比下边不太高。 Memory Barrier (Memory Fence)分为两种,一种软件的,只对编译器起作用,一种是硬件的,看文章说是总线信号控制的,这个计算机组成结构没学好,也懒得细看。 下面几种跟linux内核中的相对应,没看源码,不知道对不对 #define mb() __asm__ __volatile__("mfence":::"memory")这个跟__sync_synchronize一个作用,是硬件的栅栏。 #define rmb() __asm__ __volatile__("lfence":::"memory")不允许将barrier之前的内存读取指令移到barrier之后 (release barrier) #define wmb() __asm__ __volatile__("sfence":::"memory")不允许将barrier之后的内存读取指令移到barrier之前(acquire barrier) #define barrier() __asm__ __volatile__("":::"memory") barrier()是软栅栏, rmb wmb好像分单处理器和多处理器不一样,单处理器为软栅栏。 期间写的程序也有好多cas操作,atomic原子操作,编译器主要用的gcc的,然后直接用的gcc的,官方地址: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html

Continue