【问题标题】:Symfony doctrine entity manager injected in threadSymfony 学说实体管理器注入线程
【发布时间】:2016-01-02 08:04:02
【问题描述】:

我正在尝试在线程中使用学说实体管理器。我按照建议使用静态范围 here 。 A 类是一个 symfony 服务,并且在 service.yml 中注入了学说实体管理器

class A extends \Thread{
static $em;
public function __construct($em)
    {
    self::$em = $em;
    }
    public function run(){
       self::$em->doSomething(); //here em is null
    }
}

如何从线程中正确使用实体管理器?

更新: 正如@Mjh 建议的那样,我无法从线程共享实体管理器。但是,我可以在每个线程中都有一个 em,但这非常低效。 一个解决方案可以是构建一个在线程之间共享的容器线程类,我将在其中存储从学说查询返回的实体。实体显然会与实体管理器分离,但我只需要线程之间共享的读取缓存。

更新2: 看我的第一个答案 未解决的问题:避免为每个线程初始化一个新环境

【问题讨论】:

  • $em 可能无法序列化,这意味着您应该在线程的run 方法中执行完整的自动加载和创建实体管理器对象(或任何其他依赖类)。然而,这带来了一个问题,线程是否适合您的方法,以及它是否有助于优化任何东西。
  • 现在我们有 N 个由 php 进程启动的连接器。每个连接器都是一个 php 进程,并通过 http 请求启动。连接器从 Web 收集数据,进行数据操作 ecc... 我认为线程更好,因为我们不会每次都创建一个新的 php 进程。
  • 根据请求启动进程或生成线程绝不是一个好主意。操作系统上的线程比进程轻,但从你所说的 - 你需要一个消息队列、任务分发器和工作模式。您实现了这些,但使用了低效的方法。理想情况下,您应该将任务“推送”到队列中,然后工作人员从队列中取出任务并处理它。您正在做的是动态创建工作人员,而不是拥有一组处理任务的工作人员。
  • 感谢@Mjh 的意见。我们需要为并行化分配最大优先级,以减少最终用户的等待时间。事实上,每个连接器都必须对响应进行 Web 请求和数据操作。我认为队列不是一个好的选择。
  • 我们真正需要的是一个允许连接器共享来自理论实体管理器的数据以避免重复查询相同数据的系统。

标签: symfony doctrine-orm pthreads


【解决方案1】:

我们已经建立了一个在线程之间共享的原则缓存,扩展了一个线程安全堆栈。 警告部分代码是为了演示目的而被简化的。

class work extends \Collectable{
   protected $parameters;
   public static $doctrine_mongodb;
   public function __construct($parameters){
      $this->parameters           = $parameters;
   }
   public function run()
   {
      try{
          $loader = require __DIR__.'/../../../../../../vendor/autoload.php';
          static::$container = unserialize($this->worker->container);
          static::$doctrine_mongodb     = static::$container->get('doctrine_mongodb');
        ...
        DO WORK
        $dm     = static::$doctrine_mongodb->getManager();
        $repo   = $dm->getRepository('Bundle:Document');
        $ris    = $this->worker->doctrinecache->FindOneBy($repo, array('key' => $val));
        ...
      }catch(\Exception $e){}
   }
}

注意:在工作类中,我们有工作代码的并行执行,在那里我们可以安全地使用学说公共缓存。 共享实体管理器不一样,因为文档是分离的,但用于阅读目的是好的。如果有人需要管理实体,可以使用合并原则的方法。

   class SWorker extends \Worker{
      public $env;
      public $debug; 
      public $mongodb_cache_engine;
      public function __construct( $env, $debug, $doctrinecache, $workParams){    
         $this->workParams            = $work;    
         $this->env                   = $env; 
         $this->debug                 = $debug;
         $this->doctrinecache         = $doctrinecache  ; 
      }

      public function start($options = null){
         return parent::start(PTHREADS_INHERIT_NONE);
      }

      public function run(){
         require_once __DIR__.'/../../../../../../app/bootstrap.php.cache';
         require_once __DIR__.'/../../../../../../app/AppKernel.php';
         $kernel = new \AppKernel($this->env, $this->debug);
         $kernel->loadClassCache();
         $kernel->boot();
         $this->container = serialize($kernel->getContainer());   
      }
   }

在 Sworker 类中,我们为线程准备 symfony 环境。为此,请转至 svenpelster https://github.com/krakjoe/pthreads/issues/369

class doctrinecache  extends \Stackable{
   public function __call($MethodName, $arguments){

      $repository = array_shift($arguments);
      $documentName = $repository->getDocumentName();    
      $hash = $this->generateHash($MethodName, $documentName, $arguments);
      return $this->cacheIO($hash, $repository, $MethodName, $arguments);
   }  
   public function cacheIO($hash, $repository, $MethodName, $arguments){
       $result = isset($this["{$hash}"])? $this["{$hash}"] : NULL;
       if(!$result){
          $result = call_user_func_array(array($repository, $MethodName), $arguments); 
          $this["{$hash}"] =  $result;
       }                    
       return $result;
    }
}

最后

$doctrineCache = $this->kernel->get('doctrineCacheService');
$pool = new \Pool($workerNumber, SWorker::class, [$this->kernel->getEnvironment(), $this->kernel->isDebug(), $doctrineCache  ,$workParams]);    
while(current($works ))
{
     $pool->submit(current($works ));
     next($works);
}

$pool->shutdown();

while(current($works ))
{
     $arrayResults[] = current($works )->getResults();
     next($works);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-03
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    • 2014-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多