编程开发与计算机科学

PHP 和 Python 速查手册

方便 PHP 或 Python 开发人员快速入门另一门编程语言。

使用 Vagrant 作为开发环境

初始化虚拟机环境

下载 ubuntu-15.04-amd64.box 包文件。使用离线安装的方式:

shellvagrant box add ubuntu-15.04-amd64 file:///D:\downloads\ubuntu-15.04-amd64.box

其中 D:\downloads\ubuntu-15.04-amd64.box 是下载后的 box 文件路径。

切换到项目路径下,初始化并启动 Vagrant:

shellmkdir ~/project/devstack
cd ~/project/devstack
vagrant init ubuntu-15.04-amd64

启动并登录虚拟机系统

shellvagrant up
vagrant ssh

安装软件

更新 apt 软件库:

shellsudo apt-get update -y
sudo apt-get upgrade -y

安装需要的软件包:

shellsudo apt-get install -y git ansible libmysqld-dev mysql-server mongodb-server redis-server nginx-full supervisor uwsgi uwsgi-plugin-python python-pip python-dev python-virtualenv python-mysqldb python-mongoengine python-redis python-gevent virtualenvwrapper php5 php5-fpm php5-dev libjpeg-dev

安装第三方软件:

shellsudo dpkg -i /vagrant/elasticsearch-2.0.0.deb
sudo dpkg -i /vagrant/logstash_2.0.0-1_all.deb

禁用无用的服务:

……

HTML Entities 转换问题

用 Python 给富文本编辑器的后端做一个 HTMLPurifier 组件。各种 XSS 技巧都筛了一遍。觉得万无一失了,没想到还是栽在了坑里。

HTMLPurifier 组件使用 Python HTMLParser 来实现。HTMLParser 在处理 HTML Entities 的时候和主流的浏览器不一致。主流浏览器(FireFox、Chrome、IE)都允许省略HTML Entities末尾的分号。而 HTMLParser 的unescape 函数在处理时要求必须有结尾分号,导致后端的 HTML 过滤被绕过。

……

一个语言的诞生(Act IV)

第四幕 虚拟机指令设计

常见的两种物理处理器指令架构有:复杂指令集(CISC)、简单指令集(RISC)。前者的代表是 Intel x86 处理器,后者的代表有 MIPS、SPARC 和 ARM。

CISC 指令集的指令长度不等,多种寻址方式

一个语言的诞生(Act III)

第三幕 垃圾回收

看过微软 .net coreclr 的源代码后,觉得 Lua、PHP 和 Python 的垃圾回收代码与之相比简直就是个玩具。而 Hotspot JVM 的垃圾回收算法更加复杂。

常见的垃圾回收技术能大致分成:引用计数、标记清理、标记缩并和节点复制几种。高级的技术有垃圾分代收集、渐进及并发收集、分布式垃圾收集。复杂的垃圾回收算法会根据对象的性质和内存的使用情况来选择不同的垃圾回收算法。

……

一个语言的诞生(Act II)

第二幕 对象内存布局

那些不怎么“动态”的语言,比如C#和JAVA,一般都会把数据类型分成“值”和“引用”,值类型是分配在栈上的,引用类型是分配在堆上。而“动态”的语言,比如“PHP”和“Python”所有的数据都是动态分配在堆上的。这么做的缺点一是浪费内存,二是访问慢。浪费内存是因为PHP和Python的对象都经过重度的封装,一个简单的整型经过封装后的大小是原来的4、5倍。访问慢的原因是每次创建一个对象都要申请一次内存,而且访问对象必须通过指针,这样一搞CPU的1、2级缓存根本就没有用了嘛。

……

一个语言的诞生(Act I)

第一幕 哈希表

哈希表是动态脚本语言的基石。动态语言中,全局变量表、全局字符串表、对象虚函数表、元数据表皆为哈希表。欲实现语言,则必先实现哈希表。

哈希表原理很简单,不再赘述。不同语言实现的哈希表主要区别在于处理碰撞的机制不同。一种叫“Separate chaining”,PHP的哈希表使用了这种方式;另一种叫“Open addressing”,Lua的哈希表使用的是这种。前者发生碰撞会创建一个新的bucket,然后用链表将所有碰撞的bucket链接起来;而后者在现有的buckets中找到一个空的bucket来存放发生碰撞的key-value pair。我选择的是后一种方式,一方面是节约内存,另一方面还能节省GC开销。

……

一个语言的诞生(Prologue)

一直琢磨着自己实现一个脚本语言。因为懒,直到最近才动手。

构想中的语言语法类似ActionScript,支持GC、闭包、Lambda表达式、协程、尾递归优化、迭代器/生成器、允许(编译期)强类型绑定的可嵌入式动态脚本语言。基础类型支持NULL、布尔型、32位整型、64位长整型、双精度浮点数、元组、列表、字典、闭包、协程、对象、用户数据等。

……

跨平台 C 语言开发
  1. 通过 WIN32 宏来判断是否为 Windows 平台。64位 Windows 也会定义 WIN32 宏,此外还定义 WIN64 宏,有些编译器可能是 Windows__WIN32__WIN32_WIN64
  2. 通过 _MSC_VER 宏判断是否是VC编译器
  3. 通过 __GNUC__ 宏来判断是否为 gcc 编译器
  4. Windows 平台上的 gcc 编译器支持__declspec(dllimport)__declspec(dllexport)
  5. Linux 平台上 gcc 通过 __attribute__ ((visibility("default"))) 来导出函数
  6. VC不支持 inline 关键字,要用 __inline。可以用如下代码定义:
    C#if defined(_MSC_VER) && !defined(__cplusplus) && !defined(inline)
        #define inline __inline
    #endif
  7. 数组索引用 size_t 类型、指针运算用 uintptr_t, intptr_t, ptrdiff_t、平台无关整型用 int32_t, int64_t
  8. 64位平台上的 sizeof(long double) 是16字节(VC不支持),但是实际使用长度是12字节,4字节填充的是随机数据(绝对大坑)
  9. 如果 C 代码可能被 C++ 项目使用,最好根据 __cplusplus 宏做下判断
  10. MacOSX的平台宏是 __APPLE____MACH__(这个没确认)
  11. 补充几个编译器识别的宏:__BORLANDC____llvm____clang____WATCOMC__

……

Lua 源代码中的字节对齐

Lua 源码中定义了一个叫 L_Umaxalign 的数据类型:

ctypedef union { 
  double u; 
  void *s; 
  lua_Integer i; 
  long l; 
} L_Umaxalign;

这个结构其实是该平台上最长的数据类型。

……