关于Android Studio aapt2 的报错:AAPT2 process unexpectedly exit. Error output:

升级完as3.3之后 第一次打正式包, 遇到一个问题,打包时报错AAPT2 process unexpectedly exit. Error output: 又是个坑爹的问题, 没办法, 开始百度吧, 试了N种办法,比如在gradle-wrapper.properties中添加android.enableAapt2=false。 这个方式的意思是屏蔽as对aapt2的检测,而且这个方法在as3.1之后就被弃用了, 找了半天发现在app的 build文件下面加入
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile(‘proguard-android-optimize.txt’), ‘proguard-rules.pro’
aaptOptions.cruncherEnabled = false
aaptOptions.useNewCruncher = false
}
}

重点是aaptOptions.cruncherEnabled = false
aaptOptions.useNewCruncher = false

问题解决了, 虽然我也不清楚是什么原因。。。
————————————————
版权声明:本文为CSDN博主「萌新610521」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wojiubugaosunihaha/article/details/89914796

php swoole多进程/多线程例子

swoole的多线程其实就是多进程,进程创建太多切换的开销很大,如果能用上pthreads建议用pthreads,因为我用的是php7nts版本没办法用pthreads

swoole实例如下:

<?php
/**

  • 创建多进程
    */
    $worker_num = 6; // 默认进程数
    $workers = []; // 进程保存
    $redirect_stdout = false; // 重定向输出 ; 这个参数用途等会我们看效果
    for($i = 0; $i < $worker_num; $i++){
    $process = new swoole_process(‘callback_function’, $redirect_stdout); // 启用消息队列 int $msgkey = 0, int $mode = 2
    $process->useQueue(0, 2);
    $pid = $process->start(); // 管道写入内容
    $process->write(‘index:’.$i); $process->push(‘进程的消息队列内容’);
    // 将每一个进程的句柄存起来
    $workers[$pid] = $process;
    }

/**

  • 子进程回调
  • @param swoole_process $worker [description]
  • @return [type] [description]
    */
    function callback_function(swoole_process $worker)
    {
    $recv = $worker->pop();
    echo “子输出主内容: {$recv}”.PHP_EOL;
    //get guandao content
    $recv = $worker->read();
    $result = doTask(); echo PHP_EOL.$result.’===’.$worker->pid.’===’.$recv; $worker->exit(0);
    }

/**

  • 监控/回收子进程
    */
    while(1){
    $ret = swoole_process::wait();
    if ($ret){// $ret 是个数组 code是进程退出状态码,
    $pid = $ret[‘pid’];
    echo PHP_EOL.”Worker Exit, PID=” . $pid . PHP_EOL;
    }else{
    break;
    }
    }

/**

  • doTask
  • @return [type] [description]
    */
    function doTask()
    {
    sleep(2);
    return true;
    }
    ————————————————
    版权声明:本文为CSDN博主「fangdong88」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/fangdong88/article/details/78050135

PHP+swoole实现简单多人在线聊天群发

https://www.jb51.net/article/78316.htm

这篇文章主要介绍了PHP+swoole实现简单多人在线聊天群发 的相关资料,需要的朋友可以参考下

java

由于本文的能力有限,有好多聊天逻辑的细节没有实现,只实现了群发,具体代码如下所示:

php代码:

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576$serv = new swoole_websocket_server("127.0.0.1",3999);//服务的基本设置$serv->set(array('worker_num' => 2,'reactor_num'=>8,'task_worker_num'=>1,'dispatch_mode' => 2,'debug_mode'=> 1,'daemonize' => true,'log_file' => __DIR__.'/log/webs_swoole.log','heartbeat_check_interval' => 60,'heartbeat_idle_time' => 600,));$serv->on('connect', function ($serv,$fd){// echo "client:$fd Connect.".PHP_EOL;});//测试receive$serv->on("receive",function(swoole_server $serv,$fd,$from_id,$data){// echo "receive#{$from_id}: receive $data ".PHP_EOL;});$serv->on('open', function($server, $req) {// echo "server#{$server->worker_pid}: handshake success with fd#{$req->fd}".PHP_EOL;;// echo PHP_EOL;});$serv->on('message',function($server,$frame) {// echo "message: ".$frame->data.PHP_EOL;$msg=json_decode($frame->data,true);switch ($msg['type']){case 'login':$server->push($frame->fd,"欢迎欢迎~");break;default:break;}$msg['fd']=$frame->fd;$server->task($msg);});$serv->on("workerstart",function($server,$workerid){// echo "workerstart: ".$workerid.PHP_EOL;// echo PHP_EOL;});$serv->on("task","on_task");$serv->on("finish",function($serv,$task_id,$data){return ;});$serv->on('close', function($server,$fd,$from_id) {// echo "connection close: ".$fd.PHP_EOL;// echo PHP_EOL;});$serv->start();function on_task($serv,$task_id,$from_id,$data) {switch ($data['type']){case 'login':$send_msg="说:我来了~";break;default:$send_msg="说:{$data['msg']['speak']}";break;}foreach ($serv->connections as $conn){if ($conn!=$data['fd']){if (strpos($data['msg']['name'],"游客")===0){$name=$data['msg']['name']."_".$data['fd'];}else{$name=$data['msg']['name'];}}else{$name="我";}$serv->push($conn,$name.$send_msg);}return;}function on_finish($serv,$task_id,$data){return true;}

前端代码:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>WebSocket测试</title> <script language="javascript"type="text/javascript" src="jquery-1.12.0.min.js"> </script></head><body><h2>WebSocket Test</h2> 昵称:<input type="text" id="name" size="5" value="游客"/> <input type="text" id="content"> <button onclick="speak_to_all()">发送</button><br/><br/><textarea id="message" style="overflow-x:hidden" rows="10" cols="50"></textarea> <div id="output"></div></body> <script language="javascript"type="text/javascript"> var wsUri ="ws://127.0.0.1:3999/"; var output; function init() { output = document.getElementById("output"); testWebSocket();}function testWebSocket() { websocket = new WebSocket(wsUri); websocket.onopen = function(evt) { onOpen(evt) }; websocket.onclose = function(evt) { onClose(evt) }; websocket.onmessage = function(evt) { onMessage(evt) }; websocket.onerror = function(evt) { onError(evt) }; }function get_speak_msg(){var name=document.getElementById("name").value;var speak=document.getElementById("content").value;var json_msg='{"name":"'+name+'","speak":\"'+speak+'"}';return json_msg;}function pack_msg(type,msg){return '{"type":"'+type+'","msg":'+msg+'}';}function onOpen(evt) {append_speak("已经联通服务器.........");speak_msg=get_speak_msg();send_msg=pack_msg("login",speak_msg);doSend(send_msg);}function onClose(evt) { append_speak("俺老孙去也!");} function onMessage(evt) {append_speak(evt.data);}function onError(evt) {alert(evt.data);}function doSend(message) { websocket.send(message);}function append_speak(new_msg){document.getElementById("message").value=document.getElementById("message").value+new_msg+"\n";document.getElementById('message').scrollTop = document.getElementById('message').scrollHeight;}function speak_to_all(){send_msg=pack_msg("speak",get_speak_msg());if(document.getElementById("content").value==""){return;}doSend(send_msg);document.getElementById("content").value="";}init();</script></html>

PHP 并发扣款,保证数据一致性(悲观锁和乐观锁)

PHP 并发扣款,保证数据一致性(悲观锁和乐观锁)

业务场景分析

用户购买商品的逻辑中,需要对用户钱包的余额进行查询和扣款

异常:如果同一用户并发执行多个业务进行” 查询 + 扣款” 的业务中有一定概率出现数据不一致

Tips:如果没有做限制单一接口请求频率,用户使用并发请求的手段也有概率出现数据不一致

扣款场景

Step1: 从数据库查询用户钱包余额

SELECT balance FROM user_wallet WHERE uid = $uid;+---------+| balance |+---------+| 100     |+---------+1 row in set (0.02 sec)

Step2: 业务逻辑

Tips: 文章分享处理同一用户并发扣款一致性,检查库存啥的逻辑略过

1. 查询商品价格,比如 70 元
2. 商品价格对比余额是否足够,足够时进行扣款提交订单逻辑

if(goodsPrice <= userBalance) {    $newUserBalance = userBalance - goodsPrice;  }else {    throw new UserWalletException(['msg' => '用户余额不足']);}

Step3: 将数据库的余额进行修改

UPDATE user_wallet SET balance=$newUserBalance WHERE uid = $uid

在没有并发的情况下,这个流程没有任何问题,原有余额 100,购买 70 元的商品,剩余 30 元

异常场景

Step1: 用户并发购买业务 A 和业务 B(不同实例 / 服务),一定概率并行查询余额是 100

step1

Step2: 业务 A 和业务 B 分别扣款逻辑处理,业务 A 商品 70 结果余额 30,业务 B 商品 80 结果余额 20

step1

Step3:

1 业务 A 先进行修改,修改余额为 30

step1

2 业务 A 后进行修改,修改余额为 20

step1

此时异常出现了,原余额 100 元,业务 A 和业务 B 的商品价格总和 150 元(70+80)都购买成功且余额还剩 20 元。

异常点:业务 A 和业务 B 并行查询余额为 100

解决方案

:lock:

悲观锁

使用 Redis 悲观锁,例如抢到一个 KEY 才能继续操作,否则禁止操作

封装了一个开箱即用的 RedisLock

<?php use Ar414\RedisLock; $redis = new \Redis();$redis->connect('127.0.0.1','6379'); $lockTimeOut = 5;$redisLock = new RedisLock($redis,$lockTimeOut); $lockKey    = 'lock:user:wallet:uid:1001';$lockExpire = $redisLock->getLock($lockKey); if($lockExpire) {    try {        //select user wallet balance for uid        $userBalance = 100;        //select goods price for goods_id        $goodsPrice = 80;         if($userBalance >= $goodsPrice) {            $newUserBalance = $userBalance - $goodsPrice;            //TODO set user balance in db        }else {            throw new Exception('user balance insufficient');        }        $redisLock->releaseLock($lockKey,$lockExpire);    } catch (\Throwable $throwable) {        $redisLock->releaseLock($lockKey,$lockExpire);        throw new Exception('Busy network');    }}

乐观锁

使用 CAS(Compare And Set)

在 set 写回的时候,加上初始状态的条件 compare, 只有初始状态不变的时候才允许 set 写回成功,保证数据一致性的方法

将:

UPDATE user_wallet SET balance=$newUserBalance WHERE uid = $uid

改为:

UPDATE user_wallet SET balance=$newUserBalance WHERE uid = $uid AND balance = $oldUserBalance

这样的话并发操作时只有一个是执行成功的,根据 affect rows 是否为 1 判断是否成功

结语

  • 解决方案有很多,这只是其中一种解决方案
  • 使用 Redis 悲观锁的方案会降低吞吐量

php 高并发

https://blog.csdn.net/wx_it/article/details/105827491

php 事务处理transaction

MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!

  • 在MySQL中只有使用了Innodb数据库引擎的数据库或表才支持事务
  • 事务处理可以用来维护数据库的完整性,保证成批的SQL语句要么全部执行,要么全部不执行
  • 事务用来管理insert,update,delete语句

一般来说,事务是必须满足4个条件(ACID): Atomicity(原子性)、Consistency(稳定性)、Isolation(隔离性)、Durability(持久性)

  • 1、事务的原子性:一组事务,要么成功;要么撤回。
  • 2、稳定性 : 有非法数据(外键约束之类),事务撤回。
  • 3、隔离性:事务独立运行。一个事务处理后的结果,影响了其他事务,那么其他事务会撤回。事务的100%隔离,需要牺牲速度。
  • 4、持久性:一个事务一旦被提交,它对数据库中数据的改变就是永久的,接下来即使数据库发生故障也不应该对其有任何影响。

执行下面的程序

复制代码
$mysqli = new mysqli('localhost','root','mayi1991','mysqldemo');
if($mysqli->connect_error){
    die('数据库连接错误'.$mysqli->connect_error);
}

$sql1 = "update account set balance = balance - 2 where id = 1";
//这里故意写错指令中的balance1属性
$sql2 = "update account set balance1 = balance + 2 where id = 2";        
$result1 = $mysqli->query($sql1);
$result2 = $mysqli->query($sql2);

if(!$result1 || !$result2){
    die('操作错误'.$mysqli->error);
}else{
    die('操作成功');
}
$mysqli->close();
复制代码

虽然上面的代码有报错,但是在数据库中,id=1的balance已经改变;这样就会出现问题;

我们要的同时改变,如果有一个出错,就不改变;这个时候,我们就需要“事务控制”来保证“一致性”;

我们需要用到的方法autocommit()  commit();看下面的代码

复制代码
$mysqli = new mysqli('localhost','root','mayi1991','mysqldemo');
if($mysqli->connect_error){
    die('数据库连接错误'.$mysqli->connect_error);
}

//关闭数据库自动提交
$mysqli->autocommit(false);

$sql1 = "update account set balance = balance - 2 where id = 1";
//这里故意写错属性balance1
$sql2 = "update account set balance1 = balance + 2 where id = 2";
$result1 = $mysqli->query($sql1);
$result2 = $mysqli->query($sql2);

if(!$result1 || !$result2){
    die('操作错误'.$mysqli->error);
    $mysqli->rollback();    //事务回退
}else{
    //操作全部正确后再提交
    $mysqli->commit();
}
$mysqli->close();
复制代码

首先利用autocommit(false)方法,关闭数据库自动提交,然后当操作语句全部成功后,commit()提交到数据库;

如果操作失败,我们用rollback()方法回退。

PHP进程及进程间通信

一、引言

进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。换句话说就是,在系统调度多个cpu的时候,一个程序的基本单元。进程对于大多数的语言都不是一个陌生的概念,作为”世界上最好的语言PHP”当然也例外。

二、环境

php中的进程是以扩展的形式来完成。通过这些扩展,我们能够很轻松的完成进程的一系列动作。

  • pcntl扩展:主要的进程扩展,完成进程创建于等待操作。
  • posix扩展:完成posix兼容机通用api,如获取进程id,杀死进程等。
  • sysvmsg扩展:实现system v方式的进程间通信之消息队列。
  • sysvsem扩展:实现system v方式的信号量。
  • sysvshm扩展:实现system v方式的共享内存。
  • sockets扩展:实现socket通信。

这些扩展只能在linux/mac中使用,window下是不支持。最后建议php版本为5.5+。

相关代码:进程相关代码

三、简单的例子

一个简单的PHP多进程例子,该例子中,一个子进程,一个父进程。子进程输出5次,退出程序。

$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";
$childList = array();
$pid = pcntl_fork();
if ( $pid == -1) {
    // 创建失败
    exit("fork progress error!\n");
} else if ($pid == 0) {
    // 子进程执行程序
    $pid = posix_getpid();
    $repeatNum = 5;
    for ( $i = 1; $i <= $repeatNum; $i++) {
        echo "({$pid})child progress is running! {$i} \n";
        $rand = rand(1,3);
        sleep($rand);
    }
    exit("({$pid})child progress end!\n");
} else {
    // 父进程执行程序
    $childList[$pid] = 1;
}
// 等待子进程结束
pcntl_wait($status);
echo "({$parentPid})main progress end!";

完美,终于创建了一个子进程,一个父进程。完了么?没有,各个进程之间相互独立的,没有任何交集,使用范围严重受到现在。怎么办,哪就进程间通信(interprogress communication)呗。

四、进程间通信(IPC)

通常linux中的进程通信方式有:消息队列、信号量、共享内存、信号、管道、socket。

1.消息队列

消息队列是存放在内存中的一个队列。如下代码将创建3个生产者子进程,2个消费者子进程。这5个进程将通过消息队列通信。

$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";$childList = array();
// 创建消息队列,以及定义消息类型(类似于数据库中的库)
$id = ftok(__FILE__,'m');
$msgQueue = msg_get_queue($id);
const MSG_TYPE = 1;
// 生产者
function producer(){
    global $msgQueue;
    $pid = posix_getpid();
    $repeatNum = 5;
    for ( $i = 1; $i <= $repeatNum; $i++) {
        $str = "({$pid})progress create! {$i}";
        msg_send($msgQueue,MSG_TYPE,$str);
        $rand = rand(1,3);
        sleep($rand);
    }
}
// 消费者
function consumer(){
    global $msgQueue;
    $pid = posix_getpid();
    $repeatNum = 6;
    for ( $i = 1; $i <= $repeatNum; $i++) {
        $rel = msg_receive($msgQueue,MSG_TYPE,$msgType,1024,$message);
        echo "{$message} | consumer({$pid}) destroy \n";
        $rand = rand(1,3);
        sleep($rand);
    }
}
function createProgress($callback){
    $pid = pcntl_fork();
    if ( $pid == -1) {
        // 创建失败
        exit("fork progress error!\n");
    } else if ($pid == 0) {
        // 子进程执行程序
        $pid = posix_getpid();
        $callback();
        exit("({$pid})child progress end!\n");
    }else{
        // 父进程执行程序
        return $pid;
    }
}
// 3个写进程
for ($i = 0; $i < 3; $i ++ ) {
    $pid = createProgress('producer');
    $childList[$pid] = 1;
    echo "create producer child progress: {$pid} \n";
}
// 2个写进程
for ($i = 0; $i < 2; $i ++ ) {
    $pid = createProgress('consumer');
    $childList[$pid] = 1;
    echo "create consumer child progress: {$pid} \n";
}
// 等待所有子进程结束
while(!empty($childList)){
    $childPid = pcntl_wait($status);
    if ($childPid > 0){
        unset($childList[$childPid]);
    }
}
echo "({$parentPid})main progress end!\n";

由于消息队列去数据是,只有一个进程能去到,所以不需要额外的锁或信号量。

2. 信号量与共享内存

信号量:是系统提供的一种原子操作,一个信号量,同时只有你个进程能操作。一个进程获得了某个信号量,就必须被该进程释放掉。

共享内存:是系统在内存中开辟的一块公共的内存区域,任何一个进程都可以访问,在同一时刻,可以有多个进程访问该区域,为了保证数据的一致性,需要对该内存区域加锁或信号量。

以下,创建多个进程修改内存中的同一个值。

$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";
$childList = array();

// 创建共享内存,创建信号量,定义共享key
$shm_id = ftok(__FILE__,'m');
$sem_id = ftok(__FILE__,'s');
$shareMemory = shm_attach($shm_id);
$signal = sem_get($sem_id);
const SHARE_KEY = 1;
// 生产者
function producer(){
    global $shareMemory;
    global $signal;
    $pid = posix_getpid();
    $repeatNum = 5;
    for ( $i = 1; $i <= $repeatNum; $i++) {
        // 获得信号量
        sem_acquire($signal);
        
        if (shm_has_var($shareMemory,SHARE_KEY)){
            // 有值,加一
            $count = shm_get_var($shareMemory,SHARE_KEY);
            $count ++;
            shm_put_var($shareMemory,SHARE_KEY,$count);
            echo "({$pid}) count: {$count}\n";
        }else{
            // 无值,初始化
            shm_put_var($shareMemory,SHARE_KEY,0);
            echo "({$pid}) count: 0\n";
        }
        // 用完释放
        sem_release($signal);
        
        $rand = rand(1,3);
        sleep($rand);
    }
}
function createProgress($callback){
    $pid = pcntl_fork();
    if ( $pid == -1) {
        // 创建失败
        exit("fork progress error!\n");
    } else if ($pid == 0) {
        // 子进程执行程序
        $pid = posix_getpid();
        $callback();
        exit("({$pid})child progress end!\n");
    }else{
        // 父进程执行程序
        return $pid;
    }
}
// 3个写进程
for ($i = 0; $i < 3; $i ++ ) {
    $pid = createProgress('producer');
    $childList[$pid] = 1;
    echo "create producer child progress: {$pid} \n";
}
// 等待所有子进程结束
while(!empty($childList)){
    $childPid = pcntl_wait($status);
    if ($childPid > 0){
        unset($childList[$childPid]);
    }
}
// 释放共享内存与信号量
shm_remove($shareMemory);
sem_remove($signal);
echo "({$parentPid})main progress end!\n";

3.信号

信号是一种系统调用。通常我们用的kill命令就是发送某个信号给某个进程的。具体有哪些信号可以在liunx/mac中运行kill -l查看。下面这个例子中,父进程等待5秒钟,向子进程发送sigint信号。子进程捕获信号,掉信号处理函数处理。


$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";

// 定义一个信号处理函数
function sighandler($signo) {
    $pid = posix_getpid();
    echo "{$pid} progress,oh no ,I'm killed!\n";
    exit(1);
}

$pid = pcntl_fork();
if ( $pid == -1) {
    // 创建失败
    exit("fork progress error!\n");
} else if ($pid == 0) {
    // 子进程执行程序
    // 注册信号处理函数
    declare(ticks=10);
    pcntl_signal(SIGINT, "sighandler");
    $pid = posix_getpid();
    while(true){
        echo "{$pid} child progress is running!\n";
        sleep(1);
    }
    exit("({$pid})child progress end!\n");
}else{
    // 父进程执行程序
    $childList[$pid] = 1;
    // 5秒后,父进程向子进程发送sigint信号.
    sleep(5);
    posix_kill($pid,SIGINT);
    sleep(5);
}
echo "({$parentPid})main progress end!\n";

4.管道(有名管道)

管道是比较常用的多进程通信手段,管道分为无名管道与有名管道,无名管道只能用于具有亲缘关系的进程间通信,而有名管道可以用于同一主机上任意进程。这里只介绍有名管道。下面的例子,子进程写入数据,父进程读取数据。

// 定义管道路径,与创建管道
$pipe_path = '/data/test.pipe';
if(!file_exists($pipe_path)){
    if(!posix_mkfifo($pipe_path,0664)){
        exit("create pipe error!");
    }
}
$pid = pcntl_fork();
if($pid == 0){
    // 子进程,向管道写数据
    $file = fopen($pipe_path,'w');
    while (true){
        fwrite($file,'hello world');
        $rand = rand(1,3);
        sleep($rand);
    }
    exit('child end!');
}else{
    // 父进程,从管道读数据
    $file = fopen($pipe_path,'r');
    while (true){
        $rel = fread($file,20);
        echo "{$rel}\n";
        $rand = rand(1,2);
        sleep($rand);
    }
}

5.socket

socket即我们常说的套接字编程。这个待补充。原文地址:https://www.jianshu.com/p/08bcf724196b

PHP基于swoole多进程操作示例

https://www.jb51.net/article/167448.htm

这篇文章主要介绍了PHP基于swoole多进程操作,结合实例形式分析了php使用swoole多进程实现多个任务同时执行以及大任务划分成多个小任务相关操作技巧,需要的朋友可以参考下

java

本文实例讲述了PHP基于swoole多进程操作。分享给大家供大家参考,具体如下:

多个任务同时执行

将顺序执行的任务,转化为并行执行(任务在逻辑上可以并行执行)
比如,我们要对已知的用户数据进行判断,是否需要发送邮件和短信,如果需要发送则发送。

不使用多进程时,我们首先判断是否发送邮件,如果需要则发送;然后再判断是否需要发送短信,如果需要则发送。如果发送邮件耗时2s,发送短信耗时2s,那么我们完成任务大概需要4s左右的时间。

如果我们使用多线程的话,可以开两个线程,一个用于处理邮件,一个用于处理短信,则耗时一共需要2s左右,处理时间缩短了一半。

123456789101112131415161718192021222324252627282930313233343536373839<?php/*** Created by PhpStorm.* User: zhezhao* Date: 2016/10/20* Time: 10:37*/$info = array("sendmail"=>1,"mailto"=>"12345@qq.com","sendsms"=>1,"smsto"=>"123456");echo "start:".date("Y-m-d H:i:s").PHP_EOL;$mail_process = new swoole_process('sendMail',true);$mail_process->start();$sms_process = new swoole_process('sendSMS',true);$sms_process->start();//主进程输出子进程范围内容echo $mail_process->read();echo PHP_EOL;echo $sms_process->read();echo PHP_EOL;echo "end:".date("Y-m-d H:i:s").PHP_EOL;//并行函数function sendMail(swoole_process $worker){global $info;if($info['sendmail']==1){sleep(2);$worker->write("send mail to ".$info['mailto']);}}function sendSMS(swoole_process $worker){global $info;if($info['sendmail']==1){sleep(2);$worker->write("send sms to ".$info['smsto']);}}
这里写图片描述

大任务划分成多个小任务

将循环执行的任务,划分为多个进程执行,提高工作效率

假设我们现在有一个通过curl抓取网页内容的需求,需要抓取10个网页,url地址通过数组读取,每个curl耗时2s。如果我们通过for循环来抓取这10个网页,需要耗时20s,使用多进程我们可以将任务划分成5份,分别由5个进程执行,每个进程抓取2个url,并发执行,共耗时4s,效率提高5倍。

123456789101112131415161718192021222324252627282930313233343536<?php/*** Created by PhpStorm.* User: zhezhao* Date: 2016/10/20* Time: 10:51*/$url_arr = array();for ($i=0;$i<10;$i++){$url_arr[] = "www.baidu.com?wd=".$i;}echo "start:".date("Y-m-d H:i:s").PHP_EOL;$workers = array();for ($i=0;$i<5;$i++){$process = new swoole_process('getContents',true);$process->start();$process->write($i);$workers[] = $process;}//主进程数据结果foreach ($workers as $process){echo $process->read();echo PHP_EOL;}echo "end:".date("Y-m-d H:i:s").PHP_EOL;function getContents(swoole_process $worker){$i = $worker->read();global $url_arr;$res1 = execCurl($url_arr[($i*2)]);$res2 = execCurl($url_arr[($i*2+1)]);echo $res1.PHP_EOL.$res2;}function execCurl($url){sleep(2);return "handle ".$url." finished";}
这里写图片描述

总结

以上两种情况,本质上都是将逻辑上没有先后关系的任务,用多个进程程并发执行,提高效率。

php机制本身不提供多线程的操作,ptcl扩展提供了php操作linux多进程的接口。

个人感觉swoole的多进程process方法更加方便一些。

关于两者的比较:http://wiki.swoole.com/wiki/page/214.html

参考文章:
https://segmentfault.com/a/1190000002946586

更多关于PHP相关内容感兴趣的读者可查看本站专题:《PHP进程与线程操作技巧总结》、《PHP网络编程技巧总结》、《PHP基本语法入门教程》、《PHP数组(Array)操作技巧大全》、《php字符串(string)用法总结》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总