Symfony的实践经理注入线程 [英] Symfony doctrine entity manager injected in thread

查看:113
本文介绍了Symfony的实践经理注入线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在线程中使用教条实体管理器。我使用静态范围 here
A类是一个symfony服务,并且在service.yml注入了教义实体管理器

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

我如何使用实体经理从线程正确?



更新:
由于@Mjh建议我不能从线程共享实体管理器。我可以在每个线程中都有一个em,但是这是非常低效的。
解决方案可以构建一个在线程之间共享的容器线程类,其中我将存储从doctrine查询返回的实体。实体显然将脱离实体管理器,但我只需要在线程之间共享一个读取缓存。



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

解决方案

我们已经建立了一个在线程安全可堆叠的线程之间共享的学说缓存。
警告某些部分代码是为了演示目的而进行的。

  class work extends \Collectable {
保护$参数;
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){}
}
}

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

  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环境。 Tnx to svenpelster https://github.com/krakjoe/pthreads/issues/369 for

  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);
}


I'm trying to use doctrine entity manager in a thread. I use a static scope as suggested here . Class A is a symfony service and doctrine entity manager is injected in 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
    }
}

How i can use entity manager correctly from a thread?

UPDATE: As @Mjh suggested I can't share entity manager from threads. I can have an istance of em in every threads however but this is very inefficient. A solution could be build a container threaded class shared between threads in which I'll store the entities that return from doctrine queries. The entities obviously will be detached from entity manager but I need only a read cache shared between threads.

UPDATE2: See my first answer Open issue: avoid to initialize for every thread a new environment

解决方案

We have built a doctrine cache shared between thread extending a Thread Safe Stackable. Warning some parts of code are semplified for demo purpose.

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){}
   }
}

NB: in work class we have the parallel execution of work code and there we can safely use doctrine common cache. It's not the same to share entity manager because document are detached but for read purpose is good. If somebody need to manage entities can use merge doctrine method.

   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());   
      }
   }

In Sworker class we prepare symfony environment for thread. Tnx to svenpelster https://github.com/krakjoe/pthreads/issues/369 for that.

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;
    }
}

And finally

$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);
}

这篇关于Symfony的实践经理注入线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆