Symfony doctrine entity manager injected in thread

2019-08-13 02:00发布

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

1条回答
Root(大扎)
2楼-- · 2019-08-13 02:20

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);
}
查看更多
登录 后发表回答