Symfony的实践经理注入线程 [英] Symfony doctrine entity manager injected in thread
问题描述
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屋!