PHP pthreads v3下同步处理synchronized用法示例


Posted in PHP onFebruary 21, 2020

本文实例讲述了PHP pthreads v3下同步处理synchronized用法。分享给大家供大家参考,具体如下:

之所以会用到同步,是因为如果多个线程中对同一个资源进行操作时,会发生混乱。

比如2个线程对变量进行加1操作,第1个线程还没来的及改写数据时,第2个线程就对变量进行操作了,那变量最终的结果就是未知的,这个时候就需要同步来进行控制了。

例子如下:

<?php
class Count extends Thread
{
  public $cnt = 0;

  public function run()
  {
    $this->add();
  }

  public function add()
  {
    //对成员进行加1操作
    for ($i = 0; $i < 100000; $i++) {
      ++$this->cnt;
    }
  }
}

$c = new Count();
//调用start()时,线程run()中就调用了add()方法
$c->start();
//我们人为再调用一次add()方法,这时候就会有两个for循环对$cnt进行操作
$c->add();
//把创建的线程加入主线程中,让主线程等待子线程运行结束
$c->join();

//这里输出就是不确定性的
var_dump($c->cnt);

多次运行后,$cnt的值是不确定的。如下图所示:

PHP pthreads v3下同步处理synchronized用法示例

在pthreads v2中我们可以用Mutex,不过在v3版本中被删除了,所以我们可以简单的把加1操作放到synchronized中进行同步,代码如下:

<?php
class Count extends Thread
{
  public $cnt = 0;

  public function run()
  {
    $this->add();
  }

  public function add()
  {
    $this->synchronized(function () {
      //对成员进行加1操作
      for ($i = 0; $i < 100000; $i++) {
        ++$this->cnt;
      }
    });
  }
}

$c = new Count();
//调用start()时,线程run()中就调用了add()方法
$c->start();
//我们人为再调用一次add()方法,这时候就会有两个for循环对$cnt进行操作
$c->add();
//把创建的线程加入主线程中,让主线程等待子线程运行结束
$c->join();

//这里就会一直输出200000
var_dump($c->cnt);

结果如下所示:

PHP pthreads v3下同步处理synchronized用法示例

当然我们也可以通过notify()和wait()进行同步控制,代码如下:

<?php
class Task extends Thread
{
  public $flag = 1;

  public function run()
  {
    $this->synchronized(function () {
      //标识不为1就一直等待
      if ($this->flag !== 1) {
        $this->wait();
      }

      for ($i = 1; $i <= 10; $i++) {

        echo "flag : {$this->flag} i : {$i} \n";

        if ($this->flag === 1) {
          //设置标识
          $this->flag = 2;
          //发送唤醒通知,然后让当前线程等待
          //注意,notify()与wait()顺序不要搞错了,不然会一直阻塞
          $this->notify();
          $this->wait();
        }
      }

      //我们在这里再次调用notify()
      //因为在最后一次输出flag : 2 i : 20时,当前线程的i已经变成11了,跳出了for循环,
      //但另一个线程则一直阻塞在wait()那里,程序无法结束,所以需要notify()再次唤醒一次
      $this->notify();
    });
  }
}

$t = new Task();
$t->start();

$t->synchronized(function ($obj) {
  //标识不为2就一直等待
  if ($obj->flag !== 2) {
    $obj->wait();
  }

  for ($i = 11; $i <= 20; $i++) {

    echo "flag : {$obj->flag} i : {$i} \n";

    if ($obj->flag === 2) {
      $obj->flag = 1;
      $obj->notify();
      $obj->wait();
    }
  }
}, $t);

//把创建的线程加入主线程中,让主线程等待子线程运行结束
$t->join();

结果如下图所示:

PHP pthreads v3下同步处理synchronized用法示例

我们通过notify()和wait()控制了两个for循环,来回的输出变量i的值,保证了顺序性。

我们再来看一个复杂点的例子,共享的资源,如果不进行同步操作,会出现不可预知的情况,代码如下: 

<?php
class Task extends Thread
{
  private $name;
  private $file;

  public function __construct($name, $file)
  {
    $this->name = $name;
    $this->file = $file;
  }

  public function run()
  {
    $data = file_get_contents($this->file);
    $data = floatval($data);
    for ($i = 0; $i < 100000; $i++) {
      ++$data;
    }
    file_put_contents($this->file, $data);
    echo "task : {$this->name} data : {$data} \n";
  }
}

$tasks = [];
$file = './test.log';

for ($i = 0; $i < 100; $i++) {
  $tasks[$i] = new Task($i, $file);
  $tasks[$i]->start();
}

for ($i = 0; $i < 100; $i++) {
  $tasks[$i]->join();
}

我们开100个线程对文件test.log进行读写,理想状态下,test.log中的数据应该是每次增加10000000的。现在的电脑配置都比较好,大家可以多运行几次就可以看出效果。

PHP pthreads v3下同步处理synchronized用法示例

 很明显最后的数据好像少了200000,多线程下对test.log文件进行读写,而我们又没有加锁,显然是会出现数据混乱的。

现在我们修改一下代码,如下:

<?php
class File extends Thread
{
  private $file;

  public function __construct($file)
  {
    $this->file = $file;
  }

  public function inc()
  {
    //进行同步控制,当100个task线程调用inc方法时,synchronized可以保证块内的代码是同步的
    //注意,注意,不要把inc方法写到Task里,那样是没效果的,因为每个task线程都是独立空间,他们各自调各自的inc方法,是没法做到同步的
    //常用的做法是我们要同步哪些资源,就为这些资源写个Thread类,并提供操作这些资源的方法,并在方法里加上synchronized
    return $this->synchronized(function () {
      $data = file_get_contents($this->file);
      $data = floatval($data);
      for ($i = 0; $i < 100000; $i++) {
        ++$data;
      }
      file_put_contents($this->file, $data);
      return $data;
    });
  }
}

class Task extends Thread
{
  private $name;
  private $file;

  public function __construct($name, $file)
  {
    $this->name = $name;
    $this->file = $file;
  }

  public function run()
  {
    $data = $this->file->inc();
    echo "task : {$this->name} data : {$data} \n";
  }
}

$tasks = [];
$file = new File('./test.log');

for ($i = 0; $i < 100; $i++) {
  $tasks[$i] = new Task($i, $file);
  $tasks[$i]->start();
}

for ($i = 0; $i < 100; $i++) {
  $tasks[$i]->join();
}

结果如下图所示,当然为了保险起见,我们可以试着多运行几次,下面是我运行了25次的结果:

PHP pthreads v3下同步处理synchronized用法示例

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
可以在线执行PHP代码包装修正版
Mar 15 PHP
php中函数的形参与实参的问题说明
Sep 01 PHP
Php Image Resize图片大小调整的函数代码
Jan 17 PHP
PHP的Socket通信之UDP通信实例
Jul 02 PHP
PHP读取文件内容的五种方式
Dec 28 PHP
PHP环境搭建的详细步骤
Jun 30 PHP
浅谈PHP中的面向对象OOP中的魔术方法
Jun 12 PHP
PHP实现的各类hash算法长度及性能测试实例
Aug 27 PHP
PHP memcache在微信公众平台的应用方法示例
Sep 13 PHP
laravel migrate初学常见错误的解决方法
Oct 11 PHP
PHP简单实现解析xml为数组的方法
May 02 PHP
laravel 错误处理,接口错误返回json代码
Oct 25 PHP
PHP pthreads v3下的Volatile简介与使用方法示例
Feb 21 #PHP
PHP pthreads v3使用中的一些坑和注意点分析
Feb 21 #PHP
php使用pthreads v3多线程实现抓取新浪新闻信息操作示例
Feb 21 #PHP
php操作redis数据库常见方法实例总结
Feb 20 #PHP
php使用redis的几种常见操作方式和用法示例
Feb 20 #PHP
PHP使用openssl扩展实现加解密方法示例
Feb 20 #PHP
php使用redis的有序集合zset实现延迟队列应用示例
Feb 20 #PHP
You might like
优化NFR之一 --MSSQL Hello Buffer Overflow
2006/10/09 PHP
php快速url重写 更新版[需php 5.30以上]
2010/04/20 PHP
PHP列出MySQL中所有数据库的方法
2015/03/12 PHP
php连接MSsql server的五种方法总结
2018/03/04 PHP
PHP实现随机发放扑克牌
2020/04/21 PHP
统一接口:为FireFox添加IE的方法和属性的js代码
2007/03/25 Javascript
javascript cookies操作集合
2010/04/12 Javascript
JS下高效拼装字符串的几种方法比较与测试代码
2010/04/15 Javascript
JS实现在Repeater控件中创建可隐藏区域的代码
2010/09/16 Javascript
jQuery的运行机制和设计理念分析
2011/04/05 Javascript
鼠标放在图片上显示大图的JS代码
2013/03/26 Javascript
js获取多个tagname的节点数组
2013/09/22 Javascript
javascript Event对象详解及使用示例
2013/11/22 Javascript
jquery选择器需要注意的问题
2014/11/26 Javascript
javascript函数式编程实例分析
2015/04/25 Javascript
谈谈JSON对象和字符串之间的相互转换JSON.stringify(obj)和JSON.parse(string)
2015/10/01 Javascript
有关Promises异步问题详解
2015/11/13 Javascript
Express实现前端后端通信上传图片之存储数据库(mysql)傻瓜式教程(一)
2015/12/10 Javascript
三个js循环的关键字示例(for与while)
2016/02/16 Javascript
微信小程序通过api接口将json数据展现到小程序示例
2017/01/20 Javascript
jQuery用noConflict代替$的实现方法
2017/04/12 jQuery
mui开发中获取单选按钮、复选框的值(实例讲解)
2017/07/24 Javascript
关于前后端json数据的发送与接收详解
2017/07/30 Javascript
详解node Async/Await 更好的异步编程解决方案
2018/05/10 Javascript
Node.js爬虫如何获取天气和每日问候详解
2019/08/26 Javascript
python应用程序在windows下不出现cmd窗口的办法
2014/05/29 Python
python开发之thread线程基础实例入门
2015/11/11 Python
PyQt 实现使窗口中的元素跟随窗口大小的变化而变化
2019/06/18 Python
Python3从零开始搭建一个语音对话机器人的实现
2019/08/23 Python
python如何调用php文件中的函数详解
2020/12/29 Python
中国酒类在线零售网站:酒仙网
2016/08/20 全球购物
SK-II神仙水美国官网:SK-II美国
2020/02/25 全球购物
竞争上岗演讲稿范文
2014/05/12 职场文书
销售员未完成销售业绩的检讨书
2014/10/12 职场文书
清洁工岗位职责
2015/02/13 职场文书
python 实现德洛内三角剖分的操作
2021/04/22 Python