appserver-io/concurrency 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

appserver-io/concurrency

Composer 安装命令:

composer require appserver-io/concurrency

包简介

It introduces abstract services and objects that provides easy handling for thread-safety, concurrency and sharing.

README 文档

README

Latest Stable Version Total Downloads License Build Status Code Coverage Code Quality

What is it?

The concurrency toolkit introduces abstract services and objects that provides easy handling for thread-safety, concurrency programming and data sharing all written in PHP-Userland.

Why?

If you are implementing multithreaded functionality you're always fighting against the same problems called Race-Conditions, Deadlocks etc... When sharing simple data or even plain PHP objects between threads you have to make sure, that everything is synchronized (Thread-safe) in any logic of your code. This Toolkit mostly helps you to avoid those problems by providing abstract services and object written in PHP-Userland.

How to use?

This toolkit is in early-stage development. Please use with caution.

The ExecutorService

It allows you to hold plain PHP objects persistent as singleton in memory accessible everywhere in your code even in different thread contexts. You can keep those plain PHP objects easily thread-safe or call certain methods asynchronous by using simple annotations like @Synchronized or @Asynchronous in method docblocks.

How it works

If you want to use the concurrency toolkit in your project you have to add it to the composer dependencies composer.json and do a composer update afterwards.

{
    "require": {
        "appserver-io/concurrency": "~0.2"
    },
}

At first you have to initialise the ExecutorService in a main PHP script main.php.

<?php

define(AUTOLOADER, 'vendor/autoload.php');
require_once(AUTOLOADER);

// init executor service
\AppserverIo\Concurrecy\ExecutorService::__init(AUTOLOADER);

Lets say you want to build a simple storage PHP object to share data all over your multithreaded implementations. The storage object could look like this. Create Storage.php and add:

<?php

class Storage
{
    public $data = array();

    /**
     * @Synchronized
     */
    public function all() {
        return $this->data;
    }

    /**
     * @Synchronized
     */
    public function set($key, $value) {
        $this->data[$key] = $value;
    }

    /**
     * @Synchronized
     */
    public function get($key) {
        if ($this->has($key)) {
            return $this->data[$key];
        }
    }

    /**
     * @Synchronized
     */
    public function has($key) {
        return isset($this->data[$key]);
    }

    /**
     * @Synchronized
     */
    public function del($key) {
        unset($this->data[$key]);
    }

    /**
     * @Synchronized
     */
    public function inc($key) {
        if ($this->has($key)) {
            ++$this->data[$key];
        }
    }

    /**
     * @Asynchronous
     */
    public function dump() {
        echo var_export($this->all(), true) . PHP_EOL;
    }
}

Maybe you've noticed the method docblock annotations we used here. Methods marked with @Synchronized can not be called more than once at the same time. That means the $data array will always be synchronized when using all(), set(), get(), del() or inc(). Methods using @Asynchronous are called asynchronously. So if the dump() method is called it will dump the $data array while not blocking your main logic execution.

To make use of the storage object we have to create a multithreaded task simulation that should represent multithreaded business logic. So create Task.php and add:

<?php
class Task extends Thread {

    public static function simulate($maxThreads) {
        $t = array();
        for ($i=0; $i<$maxThreads; $i++) {
            $t[$i] = new self();
            $t[$i]->start(PTHREADS_INHERIT_ALL | PTHREADS_ALLOW_GLOBALS);
        }
        for ($i=0; $i<$maxThreads; $i++) {
            $t[$i]->join();
        }
    }

    public function run() {
        // get the storage object
        $storage = \AppserverIo\Concurrency\ExecutorService::__getEntity('data');
        // add thread signature
        $storage->set($this->getThreadId(), __METHOD__);
        // increase internal counter
        $storage->inc('counter');
    }
}

Now bring all together and enhance the main script main.php:

<?php

define('AUTOLOADER', 'vendor/autoload.php');
require_once(AUTOLOADER);
require_once('Storage.php');
require_once('Task.php');

use \AppserverIo\Concurrency\ExecutorService as ExS;

// init executor service
ExS\Core::init(AUTOLOADER);

// create storage instance with alias data
$data = ExS\Core::newFromEntity('Storage', 'data');

// preinit counter
$data->set('counter', 0);

// simulate multithreaded tasks
Task::simulate(10);

// dump data async
$data->dump();

echo 'finished' . PHP_EOL;

// shutdown executor service and its entities
ExS\Core::shutdown();

If you call main.php with a thread-safe compiled php version where pthreads ext is installed as it`s provided by appserver.io runtime for example the result should look like this:

$ /opt/appserver/bin/php bootstrap.php 
finished
array (
  'counter' => 10,
  140470559000320 => 'Task::run',
  140470550284032 => 'Task::run',
  140470541891328 => 'Task::run',
  140470327965440 => 'Task::run',
  140470319572736 => 'Task::run',
  140470311180032 => 'Task::run',
  140470302787328 => 'Task::run',
  140470294394624 => 'Task::run',
  140470286001920 => 'Task::run',
  140470277609216 => 'Task::run',
)

The executor service has some internal function as described here:

Method Description
__return Returns the plain entity object from executor thread context if its serializable in its actual state
__invoke(closure) Executes the callable in executor thread context. It will provide $self as function argument which references the plain entity object. Example usage:
$executorServiceEntity->__invoke(function($self) { $self->doSomething() }); 
__reset() Resets the plaing entity object in executor service context
__shutdown() Shutdown the executor service thread

Issues

In order to bundle our efforts we would like to collect all issues regarding this package in the main project repository's issue tracker. Please reference the originating repository as the first element of the issue title e.g.: [appserver-io/<ORIGINATING_REPO>] A issue I am having

appserver-io/concurrency 适用场景与选型建议

appserver-io/concurrency 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 4.29k 次下载、GitHub Stars 达 3, 最近一次更新时间为 2015 年 03 月 18 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「php」 「concurrency」 「sharing」 「pthreads」 「multithreading」 「thread-safty」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 appserver-io/concurrency 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 appserver-io/concurrency 我们能提供哪些服务?
定制开发 / 二次开发

基于 appserver-io/concurrency 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 4.29k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 3
  • 点击次数: 36
  • 依赖项目数: 4
  • 推荐数: 0

GitHub 信息

  • Stars: 3
  • Watchers: 3
  • Forks: 2
  • 开发语言: PHP

其他信息

  • 授权协议: OSL-3.0
  • 更新时间: 2015-03-18