未完待续…
##进程(process)
####进程的概念
进程:是系统进行资源分配和调度的基本单位
####php如何创建子进程
0) {
//parent process
} else {
//child process
//这里一般会退出,不然子进程不退出,会执行到下面主程序的代码
exit(0);
}
//这一行代码是父子都会执行的,所以上面在子程序的else里面用了exit
echo 'hello world';
####修改进程名称
function setProcessName($name)
{
// >=php 5.5
if (function_exists('cli_set_process_title')) {
@cli_set_process_title($name);
} elseif (extension_loaded('proctitle') && function_exists('setproctitle')) {
@setproctitle($name);
}
}
ps -ef |grep pname/pid
####进程组、会话
–进程组:
–会话:
####php中启动daemon进程
0) {
// parent child
exit(0);
}
//set child process to session leader
if (-1 === posix_setsid()) {
throw new Exception('setsid fail');
}
//fork again out terminal
$pid = pcntl_fork();
if (-1 === $pid) {
throw new Exception("fork fail");
} elseif (0 !== $pid) {
exit(0);
}
}
daemonize();
//下面的代码都是在daemon进程中执行了
echo 'hello world';
####信号
pcntl_signal_dispatch()和ticks完成了一样的功能
0) {
echo 'parent pid=' . posix_getpid();
$pid_arr[] = $pid;
} elseif ($pid == 0) {
echo 'child pid=' . posix_getpid();
exit(0); //子进程退出
}
}
//如果存在子进程
if (count($pid_arr) > 0) {
foreach ($pid_arr as $_pid) {
//发送杀死信号到子进程
posix_kill($_pid, SIGTERM);
//等待子进程退出
$return_pid = pcntl_waitpid($_pid, $status);
if ($return_pid == $_pid) {
echo "process pid=$_pid stoped";
}
}
}
####IPC(信号量,消息,共享内存)
–信号量
信号量是一个计数器,用户多进程对共享数据对象的存取。
信号量值为正,进程使用该资源,信号量减1,表明该进程已经使用了一个资源单位
若此信号量为0,则进程进入休眠状态,等信号量 +1后进程被唤醒
–消息
两个进程相互发送消息,并且接受消息的例子
class TestMsg {
public static $MSGKEY = 12345;
public function run() {
for ($i = 0; $i < 2; $i++) {
$pid = pcntl_fork();
if ($pid == -1) {
die('fork fail');
} elseif ($pid > 0) { //parent
//
} elseif ($pid == 0) {//child
$this->send_msg($i);
$tmpkey = ($i == 0) ? 1 : 0;
$message = $this->recv_msg($tmpkey);
echo "i=$i, message=$message || ";
exit(0);
}
}
}
public function send_msg($i) {
$msgkey = self::$MSGKEY+ $i;
$msg_id = msg_get_queue($msgkey);
$content = self::$MSGKEY . '_' . $i;
if (!msg_send ($msg_id, 1, $content, true, true, $msg_err)) {
echo "because $msg_err";
}
}
public function recv_msg($i) {
$msgkey = self::$MSGKEY+ $i;
$msg_id = msg_get_queue($msgkey);
while(1) {
if (msg_queue_exists($msgkey)) {
//读取
msg_receive($msg_id, 1, $msg_type, 16384, $message);
//读取后删除这条消息
msg_remove_queue($msg_id);
return $message;
}
sleep(2);
continue;
}
}
}
$msg = new TestMsg();
$msg->run();
查看ipc的一些命令
ipcs用法
ipcs -a 是默认的输出信息 打印出当前系统中所有的进程间通信方式的信息
ipcs -m 打印出使用共享内存进行进程间通信的信息
ipcs -q 打印出使用消息队列进行进程间通信的信息
ipcs -s 打印出使用信号进行进程间通信的信息
输出格式的控制
ipcs -t 输出信息的详细变化时间
ipcs -p 输出ipc方式的进程ID
ipcs -c 输出ipc方式的创建者/拥有者
ipcs -c 输出ipc各种方式的在该系统下的限制条件信息
ipcs -u 输出当前系统下ipc各种方式的状态信息(共享内存,消息队列,信号)
ipcrm 命令
移除一个消息对象。或者共享内存段,或者一个信号集,同时会将与ipc对象相关链的数据也一起移除。当然,只有超级管理员,或者ipc对象的创建者才有这项权利啦
ipcrm用法
ipcrm -M shmkey 移除用shmkey创建的共享内存段
ipcrm -m shmid 移除用shmid标识的共享内存段
ipcrm -Q msgkey 移除用msqkey创建的消息队列
ipcrm -q msqid 移除用msqid标识的消息队列
ipcrm -S semkey 移除用semkey创建的信号
ipcrm -s semid 移除用semid标识的信号
##线程(pthread)
##协程(coroutine)
协程:即是用户态完成程序的调度,像系统调度进程和线程一样,只不过是每次切换的时候又用户完成堆栈和寄存器中的数值的保存,并记录可以恢复到这个上下文执行。自己这样实现就是协程了。
-实现协程的几种方式
1. 使用setjmp和longjmp跳转来实现上下文的恢复来实现协程。
2. 使用ucontext库函数来实现协程。
3. 云风的协程库,腾讯开源的libco协程库
##常见的进程模型
##多路复用
有一篇文章一看就懂
地址:
多路复用图解
概念
多路复用通常表示在一个信道上传输多路信号或数据流的过程和技术
在做网络编程的时候,我们会经常碰到阻塞(Blocking)与非阻塞(Non-Blocking)、同步(Synchronous)与异步(Asynchronous)的概念。这两组概念很相近,容易混淆。
阻塞和非阻塞是用来描述I/O操作的:在执行 I/O操作时,如果数据没有准备好,阻塞模式下会一直等待直到准备好或者超时,非阻塞模式下会立即返回。
同步与异步是用来描述消息传递方式:同步模式下,接收方需要不断地主动向发送方查询消息;异步模式下,发送方会主动将消息送给接收方。
体现在程序上就是线程卡主,一个线程不卡主
本质上两组概念是没有关联的,不过我们会经常看到异步非阻塞的词语,这是因为在实际I/O处理时都有应用场景。处理I/O操作时,需要及时知道I/O状态及操作结果等消息。在Server端,通常会用异步的消息传递方式及非阻塞I/O以提高并发吞吐效率
#####php中实现异步非堵塞
set_time_limit(0);
class EpollSocketServer
{
private static $socket;
private static $connections;
private static $buffers;
function EpollSocketServer ()
{
global $errno, $errstr;
if (!extension_loaded('libevent')) {
die("extension libevent no exists");
}
$socket_server = stream_socket_server("tcp://0.0.0.0:1234", $errno, $errstr);
if (!$socket_server) die("$errstr ($errno)");
stream_set_blocking($socket_server, 0); // 非阻塞
$base = event_base_new();
$event = event_new();
event_set($event, $socket_server, EV_READ | EV_PERSIST, array(__CLASS__, 'ev_accept'));
event_base_set($event, $base);
event_add($event);
event_base_loop($base);
}
function ev_accept($socket, $flag)
{
$conn = stream_socket_accept($socket, 60);
stream_set_blocking($conn, 0);
// Compatible with hhvm
if (function_exists('stream_set_read_buffer')) {
stream_set_read_buffer($conn, 0);
}
//第二次使用事件,我的坑爹的啊
$base = event_base_new();
$event = event_new();
event_set($event, $conn, EV_READ | EV_PERSIST, array(__CLASS__, 'ev_accept2', $base));
event_base_set($event, $base);
event_add($event);
event_base_loop($base);
}
public function ev_accept2($socket, $flag, $event) {
$buffer = fread($socket, 1024);
if ($buffer === '' || $buffer === false) {
event_del($event);
return;
}
fwrite($socket, $buffer);
}
}
new EpollSocketServer();
##apache的进程模型
##nginx的进程模型
##tomcat的进程模型
##mysql的进程模型
##memcache和redis的进程模型