-
Значит так.
Есть пул потоков QueueUserWorkItem, в callback методе
потока очереди
инициализится COM и создаётся COM-объект(Perl-скрипт мутящий текстовый файл по регулярному выражению).
К примеру, я создаю пул из 60 потоков и пихаю в каждый поток по одному заданию(текст+регулярное выражение), так вот странным образом, хотя и создаётся очередь из 60 потоков, обрабатывается корректно примерно 95% очереди, некотрорые потоки из пула странным образом не выполняются, и при этом никаких эксэпшынов не происходит в потоке.
Господа, что это может быть, в чем я туплю ?
=======CALLBACK функция для QueueUserWorkItem=========
function qGrepex(Value:Pointer):dword; stdcall;
//label LOOP;
var
outs,rx,txt:string;
ghost : OleVariant;
val : TSIREXSValue;
I: Integer;
begin
try
Val := TSIREXSValue(Value^);
rx := val.rx;
txt := val.txt;
try
CoInitializeEx
(nil,COINIT_APARTMENTTHREADED);
Ghost := CreateOleObject('psirexuwz.wsc'); //
finally
InterlockedIncrement(SIUtils.GPooled);
Ghost.grepex(rx,txt); // вызываю метод из скрипта.
while outs='' do sleep(50);
InterlockedDecrement(SIUtils.GPooled);
InterlockedDecrement(siutils.GEventCounter);
CoUninitialize;
end;
except
on E:Exception do Tsrvc.PostLog('qGrepex :: '+E.Message);
end;
result := 0ж
end;
==================================================
====================Perl-скрипт=====================
<?xml version="1.0"?>
<component>
<?component error="true" debug="true"?>
<registration
description="psirexuwz"
progid="psirexuwz.WSC"
version="2.00"
classid="{dabdb3f5-197a-403f-bc59-68094655e5f7}"
>
</registration>
<public>
<method name="grepex" dispid = "1">
<PARAMETER name="RegexPattern"/>
<PARAMETER name="Filename"/>
</method>
<method name="stoop" dispid="2">
</method>
</public>
<script language="PerlScript">
<![CDATA[
#use strict;
use threads;
use File::Basename;
my $wrk=0;
sub get_sum_len
{
my ($x,@indata);
my ($res,$i) = 0;
my @dout;
($x,@indata) = @_;
for($i=0;$i<$x;$i++)
{
$res = ($res + length($indata[$i]));
$dout[$i] = $i<=0?$res:$res-length($indata[$i]);
}
return @dout;
}
sub grepex{
open(in0,$_[0]);
open(in00,$_[1]);
open(in000,">".dirname($_[0])."\\xfile");
exit if -e dirname($_[0])."\\rslt";
my $d1r = ">".dirname($_[0])."\\rslt";
open(out0,$d1r);
my (@data,@dout,@expr,@res);
my ($dlen,$exp,$cnt,$j) ;
my ($i,$cpos,$gcpos,$llen,$flag);
@data = <in00> ;
@expr = <in0> ;
$dlen = scalar(@data);
@dout = get_sum_len($dlen,@data);
eval
{
foreach $exp(@expr)
{
if($wrk == 0)
{
$cnt+=1;
for($i=0;$i<$dlen;$i++)
{
while($data[$i]=~m/$exp/gxc)
{
$cpos = (pos($data[$i]) - length($&)) ;
$gcpos = ($dout[$i] + $cpos);
$res[$j++] = $cnt."p".
($gcpos+($i)."l".length($&))."m".$&."\n";
}
}
}
}
}
$res[0]=$@ if $@;
$res[0]=($res[0] eq ""? '$nrslt$':$res[0]);
print out0 @res;
close(out0);
close(in0);
close(in00);
return join('',@res);
@res="";
}
====================Perl-скрипт=====================
]]>
</script>
</component> -
Сергей М. © (27.10.08 21:28) [1]
> в чем я туплю ?
Первая же "тупость", бросающаяся в глаза:
> while outs='' do sleep(50);
Что это за танцы с бубном ?
Кто и где изменяет содержимое переменной outs, так чтобы выполнилось условие выхода из цикла ? -
а разве так можно?
CoInitializeEx(nil,COINIT_APARTMENTTHREADED);
а CALLBACK функция для QueueUserWorkItem может менять поток (если не WT_EXECUTEINPERSISTENTTHREAD), т.е. с COM объектом созданным в одном потоке работа может происходить в нескольких других потоках тем более что ты принудительно усыпляешь sleep поток что может повлеч за собой переключение потока на другой колбек
http://vsokovikov.narod.ru/New_MSDN_API/Process_thread/thread_pool.htm
Обратите внимание! на то, что объединение потоков в пул не совместимо с моделью однопоточных апартаментов (STA). -
ааа,
while outs='' do sleep(50);
это я забыл закаментить, это сейчас не используется.
это я сделал для того, что бы поток из пула дождался результата из скрипта, потому как я думал, что поток завершается преждевременно.
-----------------------------------------------------------------------
Самое интересное, что с этим-то флагом COINIT_APARTMENTTHREADED, всё работает нормально, потоки добавляются в пул ,но как я уже сказал, всреднем, 5% потоков не выполняются корректно , хотя никаких исключений не вылазит. Если же ставлю флаг COINIT_MULTITHREADED, то пул так же создается, но активно выполняется один поток, все остальные ждут и в этом случае всё потоки выполняют работу корректно.
Скрипт регистрируется в реестре с ключём InprocServer32->ThreadingModel->Apartment -
ну все верно... когда по очереди все нормально проходят через узкую дверь... а когда "толпой" 5% в давке загибаются...
попробуй 1 раз COINIT_MULTITHREADED перед запуском пула, из калбека убери может само "синхронизируется" :) -
пардон , я нагнал, даже когда COINIT_MULTITHREADED , и работает один поток, всё-равно пропускает задания, казлина )=
-
не проще пересмотреть задачу и наити другое более линейное решение? без пула никак? в 1 потоке? или в CPUCount потоках?
я к тому что всеравно активно будет не более CPUCount потоков...
CreateOleObject('psirexuwz.wsc') креатится постоянно... зачем? он stateless -
Slym © (28.10.08 13:31) [6]
пулы не для этого придуманы...
придуманы они для распараллеливания часто простаивающих процедур для минимизации колва потоков и расходов с ними связанных: переключения потоков, стекпамять и т.п. и т.д.
Но у тебя узкое место далеко не этом... только хуже делаешь...
расходы при взаимодействии с COM подсистемой CoInitializeEx/CoUninitialize/CreateOleObject('psirexuwz.wsc') намного превысят "доходы" от QueueUserWorkItem -
CreateOleObject('psirexuwz.wsc') креатится постоянно... зачем? он stateless
----------------------------------------------------------------------------
если я создаю единожды CreateOleObject('psirexuwz.wsc') в другом потоке, и передаю OleVariant переменную в callback метод потока, то вылазит экцэпшн... но я перепроверю ещё раз.
----------------------------------------------------------------------------
не проще пересмотреть задачу и наити другое более линейное решение? без пула никак? в 1 потоке? или в CPUCount потоках?
----------------------------------------------------------------------------
Дело в том что, на вычисление регулярного выражения будут поступать огромные логи до 1ГБ, с множества (до 10000) клиентов, поэтому было решено юзать пул. Ну тоесть один раз при старте сервиса создаётся определённое кол-во потоков, в которые пихаются задачи. -
K1LLADR1LLA © (28.10.08 13:59) [8]
на вычисление регулярного выражения будут поступать огромные логи до 1ГБ
ИЧЁ? стопудофф линейно без пулофф (при текущей реализации) быстрее буит...програм1
делаем потоки по колву процессоров
впотоке.еХекут
{
КоИнит;
обж:=КреатОбжект('psirexuwz.wsc');
дотехпорпокаживу дуит
{
задача:=ядро.дайзадачу
обж.коитус(задача)
ядро.яеёоткоитовал(задача)
}
КоДеИнит;
} -
смысла перевода непосредственного выполнения кода в теле потока в APC спящего потока я не вижу...
-
мг, я буду иметь ввиду выше предложенное, хотя я уже мудохаюсь неделю ((=
Если смысла не видно, то это ещё не значит, что смысла нет ((=