淘宝技术专家
# 大白话聊聊分布式事务 ## 什么是分布式事务 简单的来说就是,一个大的操作由两个或者更多的小的操作共同完成。而这些小的操作又分布在不同的网络主机上。这些操作,要么全部成功执行,要么全部不执行。 拿转账的例子来说下什么是分布式事务。张三和李四在不同的城市,存储他们账户信息的服务器也在不同的网络主机上。张三有30元钱,李四有30元钱。张三给李四转账5元就是一个事务。完成这个事务,需要两个
# 聊聊Swoole2.0协程 Swoole 2.0正式版发布了。2.0版本最大的更新是增加了对协程(Coroutine)的支持。正式版已同时支持PHP5和PHP7。基于Swoole2.0协程PHP开发者可以已同步的方式编写代码,底层自动进行协程调度,转变为异步IO。解决了传统异步编程嵌套回调的问题。 目前Swoole底层内置的协程客户端组件包括:udpclient、tcpclient、h
本文是以PHP7作为基础,讲解如何从零开始创建一个PHP扩展。本文主要讲解创建一个扩展的基本步骤都有哪些。示例中,我们将实现如下功能: ``` php ``` 输出内容: ``` php $ php ./test.php $ hello word ``` 在扩展中实现一个say方法,调用say方法后,输出 hello word。 # 扩展开发步骤 ## 第一步:生成
# 前言 这次,我们将演示如何在PHP扩展中接受传入的参数和输出返回值。 ``` php ``` 我们将在扩展中实现`default_value`方法。 # 代码 ## 基础代码 这个扩展,我们将在say扩展上增加 ``default_value`` 方法。say扩展相关代码大家请看这篇博文。PHP7扩展开发之hello word 文中已经详细介绍了如何创建一个扩展和提供了源
# 前言 这次,我们将演示如何在PHP扩展中如何对类型进行一些操作。如,判断变量类型。要实现的PHP代码如下: ```php ``` 分别获取string 和 array的长度。 # 代码 ## 基础代码 这个扩展,我们将在say扩展上增加 ``get_size`` 方法。say扩展相关代码大家请看这篇博文。[PHP7扩展开发之hello word](http:/
# 前言 这次,我们将演示如何在PHP扩展中如何对数组进行处理。要实现的PHP代码如下: ```php ``` 把两个数组,相同key的字符串值拼接。 # 代码 ## 基础代码 这个扩展,我们将在say扩展上增加 ``array_concat`` 方法。say扩展相关代码大家请看这篇博文。[PHP7扩展开发之hello word](http://www.bo56.com
# 前言 在这篇博文中我们将演示如何在PHP扩展中创建一个变量。示例代码如下: ```php ``` 中间的三行我们将用PHP扩展来实现。 # 代码 ##基础代码 这个扩展,我们将在say扩展上增加 `define_var` 方法。say扩展相关代码大家请看这篇博文。[PHP7扩展开发之hello word](http://www.bo56.com/php7%E6%89%A9
# PHP7扩展开发之字符串处理 # 前言 这次,我们来看看字符串在PHP扩展里面如何处理。 示例代码如下: ```php ``` 上面的str_concat方法实现了如下功能: 1、当字符串不包含指定前缀字符串时,把前缀字符串和被检测字符合并返回。 2、当字符串包含指定前缀字符串时,原样返回。 我们将使用PHP扩展的方式实现str_concat功能。 # 代码 ##
# 前言 这次,我们将演示如何在PHP扩展中定义一个常量。要实现的PHP代码如下: ``` php ``` 我们将演示在PHP扩展中定义三个常量。如上面代码中的三个define。 # 代码 ## 基础代码 这个扩展,我们将在say扩展的 ``PHP_MINIT_FUNCTION(say)`` 方法上增加相应的代码。say扩展相关代码大家请看这篇博文。[PHP7扩展开发之
本篇文章主要将如何在扩展中创建一个对象。创建的对象的过程,其实和一个小孩出生,成长的过程有些类似。 ##第一步,办准生证 生孩子第一步,先办准生证。声明我要生孩子了。对象创建的时候,如何办准生证呢?只要定义一个zend_class_entry变量即可。代码如下: ```c zend_class_entry ce; ``` zend_class_entry 是啥?可以认为它使一个原型
#前言 这篇文章不是教你如何安装使用xhprof进行性能分析。如果想了解如何安装使用xhprof,网络上文章很多,你也可以看我之前写的两篇文章。 [非侵入式监控PHP应用性能监控分析](http://www.bo56.com/%e9%9d%9e%e4%be%b5%e5%85%a5%e5%bc%8f%e7%9b%91%e6%8e%a7php%e5%ba%94%e7%94%a8%e6%80%a7%
对socket_read的返回值做下判断。如果返回-1,则对errno多下判断。socket_last_error() 方法获取errno。
给你一段用C语言写的示例。
执行命令 sestatus
如果输出内容不是 disabled
执行命令 setenforce disabled
一般编程语言都会有作用域的概念。如果,变量已经不再作用域了,变量所占用的资源还不释放,那就太浪费内存空间了。除非必要,否则会也不会干费力不讨好的事情。
贴一段代码。
输出结果
0
不错啊
其实主要是为了容灾,把数据把多地保存多份。如果一个地方数据出现问题,尽量能做到无缝切换。
你看下你的代码。连接数据库的时候主机名是不是写的 localhost? 如果是 你改成 127.0.0.1 试试。
有过简单的了解,他和nodejsyou很多相同的特点。如
1、事件驱动,异步执行,非阻塞IO
2、单进程单线程
更多信息可以查看 ReactPHP,PHP版的Node.js
开始,把php_tclip.h中的全局变量声明部分修改为如下:
ZEND_BEGIN_MODULE_GLOBALS(tclip)
CascadeClassifier face_cascade;
char *face_config_path;
ZEND_END_MODULE_GLOBALS(tclip)
结果报如下错误:
error: ‘CascadeClassifier’ does not name a type
看来这个类没有在头文件中声明。那就另辟蹊径,改为其它方式。把代码改为
ZEND_BEGIN_MODULE_GLOBALS(tclip)
void *face_cascade;
char *face_config_path;
ZEND_END_MODULE_GLOBALS(tclip)
然后在tclip.c中进行了如下修改:
1.首先定义了一个全局变量。
static CascadeClassifier face_cascade;
2.修改PHP_MINIT_FUNCTION(tclip)。代码如下:
PHP_MINIT_FUNCTION(tclip)
{
/* If you have INI entries, uncomment these lines */
REGISTER_INI_ENTRIES();
string face_config_path = (TCLIP_G(face_config_path) == "" || TCLIP_G(face_config_path) == NULL)? "/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml" :TCLIP_G(face_config_path);
if( !face_cascade.load( face_config_path ) ){
php_error_docref(NULL TSRMLS_CC, E_WARNING, "can not load classifier file!%s", face_config_path.c_str());
return FAILURE;
}
TCLIP_G(face_cascade) = &face_cascade;
return SUCCESS;
}
调用全局对象的方式如下:
((CascadeClassifier *)TCLIP_G(face_cascade))->detectMultiScale( img_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) );
注意,php扩展想线程安全,那就用相关宏来访问全局变量。如上面的TCLIP_G(face_cascade)。
参考资料 php扩展中如何定义线程安全的全局对象
闲话少说,直接上代码:
下面是我在config.m4中写的自动加载opencv相关so库和头文件的代码。
dnl # --with-tclip -> check with-path
SEARCH_PATH="/usr/lib/pkgconfig" # 定义pkgconfig文件,即扩展名pc文件存放路径
SEARCH_FOR="opencv.pc" # 要寻找的文件
if test -r $PHP_TCLIP/$SEARCH_FOR; then #
TCLIP_DIR=$PHP_TCLIP
else # search default path list
AC_MSG_CHECKING([for tclip files in default path])
for i in $SEARCH_PATH ; do
if test -r $i/$SEARCH_FOR; then
TCLIP_DIR=$i
AC_MSG_RESULT(found in $i)
fi
done
fi
dnl
if test -z "$TCLIP_DIR"; then
AC_MSG_RESULT([not found])
AC_MSG_ERROR([Please reinstall the tclip distribution])
fi
OPENCV_FLAGS="pkg-config opencv --libs --cflags opencv
"
for i in $OPENCV_FLAGS;do
if test ${i:0:2} = "-I" ;then
PHP_ADD_INCLUDE(${i:2})
elif test ${i:${#i}-3} = ".so" ;then
dir_name=`dirname $i`
file_name=${i/$dir_name/}
file_name=${file_name/\/lib/}
file_name=${file_name/.so/}
PHP_ADD_LIBRARY_WITH_PATH($file_name,$dir_name,TCLIP_SHARED_LIBADD)
fi
done
示例代码:
/*
function curl($urls = array(), $callback = '')
{
$response = array();
if (empty($urls)) {
return $response;
}
$chs = curl_multi_init();
$map = array();
foreach($urls as $url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_NOSIGNAL, true);
curl_multi_add_handle($chs, $ch);
$map[strval($ch)] = $url;
}
do{
if (($status = curl_multi_exec($chs, $active)) != CURLM_CALL_MULTI_PERFORM) {
if ($status != CURLM_OK) { break; } //如果没有准备就绪,就再次调用curl_multi_exec
while ($done = curl_multi_info_read($chs)) {
$info = curl_getinfo($done["handle"]);
$error = curl_error($done["handle"]);
$result = curl_multi_getcontent($done["handle"]);
$url = $map[strval($done["handle"])];
$rtn = compact('info', 'error', 'result', 'url');
if (trim($callback)) {
$callback($rtn);
}
$response[$url] = $rtn;
curl_multi_remove_handle($chs, $done['handle']);
curl_close($done['handle']);
//如果仍然有未处理完毕的句柄,那么就select
if ($active > 0) {
curl_multi_select($chs, 0.5); //此处会导致阻塞大概0.5秒。
}
}
}
}
while($active > 0); //还有句柄处理还在进行中
curl_multi_close($chs);
return $response;
}
//使用方法
function deal($data){
if ($data["error"] == '') {
echo $data["url"]." -- ".$data["info"]["http_code"]."\n";
} else {
echo $data["url"]." -- ".$data["error"]."\n";
}
}
$urls = array();
for ($i = 0; $i < 10; $i++) {
$urls[] = 'http://www.baidu.com/s?wd=etao_'.$i;
$urls[] = 'http://www.so.com/s?q=etao_'.$i;
$urls[] = 'http://www.soso.com/q?w=etao_'.$i;
}
curl($urls, "deal");
参考资料 php实现并发处理之curl篇
有很多中方式,这里说一种cas的方式。
其实这里并不是严格的CAS,而是使用了比较交换原子操作的思想。
生成思路如下:
每次生成全局id时,先从sequence表中获取当前的全局最大id。然后在获取的全局id上做加1操作。把加1后的值更新到数据库。更新时是关键。
如加1后的值为203,表名是users,数据表结构如下:
CREATE TABLE SEQUENCE
(
`name` varchar(30) NOT NULL COMMENT '分表的表名',
`gid` bigint(20) NOT NULL COMMENT '最大全局id',
PRIMARY KEY (`name`)
) ENGINE=InnoDB
那么更新语句是。
update sequence set gid = 203 where name = 'users' and gid < 203;
sql语句的 and gid < 203 是为了保证并发环境下gid的值只增不减。
如果update语句的影响记录条数为0说明,已经有其他进程提前生成了203这个值,并写入了数据库。需要重复以上步骤从新生成。
代码实现如下:
//$name 表名
function next_id_db($name){
//获取数据库全局sequence对象
$seq_dao = Wk_Sequence_Dao_Sequence::getInstance();
$threshold = 100; //最大尝试次数
for($i = 0; $i < $threshold; $i++){
$last_id = $seq_dao->get_seq_id($name);//从数据库获取全局id
$id = $last_id +1;
$ret = $seq_dao->set_seq_id($name, $id);
if($ret){
return $id;
break;
}
}
return false;
}
更多方式,可以查看 数据库分表后,并发环境下,生成全局id生成的几种方式
nginx的ngx_http_limit_req_module模块限制了百度蜘蛛的抓取频率。每分钟允许百度蜘蛛抓取200次,多余的抓取请求返回503。
nginx的配置:
limit_req_zone $anti_spider zone=anti_spider:60m rate=200r/m;
limit_req zone=anti_spider burst=5 nodelay;
if ($http_user_agent ~* "baiduspider") {
set $anti_spider $http_user_agent;
}
参数说明:
指令limit_req_zone 中的rate=200r/m 表示每分钟只能处理200个请求。
指令limit_req 中的burst=5 表示最大并发为5。即同一时间只能同时处理5个请求。
指令limit_req 中的 nodelay 表示当已经达到burst值时,再来新请求时,直接返回503
IF部分用于判断是否是百度蜘蛛的user agent。如果是,就对变量$anti_spider赋值。这样就做到了只对百度蜘蛛进行限制了。