Конференция "WinAPI" » Windows Script Host + COM + ThreadPool [D7, WinXP]
 
  • K1LLADR1LLA © (27.10.08 17:53) [0]
    Значит так.
    Есть пул потоков 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, так чтобы выполнилось условие выхода из цикла ?
  • Slym © (28.10.08 04:53) [2]
    а разве так можно?
    CoInitializeEx(nil,COINIT_APARTMENTTHREADED);
    а CALLBACK функция для QueueUserWorkItem может менять поток (если не WT_EXECUTEINPERSISTENTTHREAD), т.е. с COM объектом созданным в одном потоке работа может происходить в нескольких других потоках тем более что ты принудительно усыпляешь sleep поток что может повлеч за собой переключение потока на другой колбек

    http://vsokovikov.narod.ru/New_MSDN_API/Process_thread/thread_pool.htm

    Обратите внимание! на то, что объединение потоков в пул не совместимо с моделью однопоточных апартаментов (STA).
  • K1LLADR1LLA © (28.10.08 09:37) [3]
    ааа,
    while outs='' do sleep(50);
    это я забыл закаментить, это сейчас не используется.
    это я сделал для того, что бы поток из пула дождался результата из скрипта, потому как я думал, что поток завершается преждевременно.
    -----------------------------------------------------------------------
    Самое интересное, что с этим-то флагом COINIT_APARTMENTTHREADED, всё работает нормально, потоки добавляются в пул ,но как я уже сказал, всреднем, 5% потоков не выполняются корректно , хотя никаких исключений не вылазит. Если же ставлю флаг COINIT_MULTITHREADED, то пул так же создается, но активно выполняется один поток, все остальные ждут и в этом случае всё потоки выполняют работу корректно.
    Скрипт регистрируется в реестре с ключём InprocServer32->ThreadingModel->Apartment
  • Slym © (28.10.08 11:54) [4]
    ну все верно... когда по очереди все нормально проходят через узкую дверь... а когда "толпой" 5% в давке загибаются...
    попробуй 1 раз COINIT_MULTITHREADED перед запуском пула, из калбека убери может само "синхронизируется" :)
  • K1LLADR1LLA © (28.10.08 13:13) [5]
    пардон , я нагнал, даже когда COINIT_MULTITHREADED , и работает один поток, всё-равно пропускает задания, казлина )=
  • Slym © (28.10.08 13:31) [6]
    не проще пересмотреть задачу и наити другое более линейное решение? без пула никак? в 1 потоке? или в CPUCount потоках?
    я к тому что всеравно активно будет не более CPUCount потоков...

    CreateOleObject('psirexuwz.wsc') креатится постоянно... зачем? он stateless
  • Slym © (28.10.08 13:38) [7]
    Slym ©   (28.10.08 13:31) [6]
    пулы не для этого придуманы...
    придуманы они для распараллеливания часто простаивающих процедур для минимизации колва потоков и расходов с ними связанных: переключения потоков, стекпамять и т.п. и т.д.

    Но у тебя узкое место далеко не этом... только хуже делаешь...
    расходы при взаимодействии с COM подсистемой CoInitializeEx/CoUninitialize/CreateOleObject('psirexuwz.wsc') намного превысят "доходы" от QueueUserWorkItem
  • K1LLADR1LLA © (28.10.08 13:59) [8]
    CreateOleObject('psirexuwz.wsc') креатится постоянно... зачем? он stateless
    ----------------------------------------------------------------------------
    если я создаю единожды CreateOleObject('psirexuwz.wsc') в другом потоке, и передаю OleVariant переменную в callback метод потока, то вылазит экцэпшн... но я перепроверю ещё раз.
    ----------------------------------------------------------------------------
    не проще пересмотреть задачу и наити другое более линейное решение? без пула никак? в 1 потоке? или в CPUCount потоках?
    ----------------------------------------------------------------------------
    Дело в том что, на вычисление регулярного выражения будут поступать огромные логи до 1ГБ, с множества (до 10000) клиентов, поэтому было решено юзать пул. Ну тоесть один раз при старте сервиса создаётся определённое кол-во потоков, в которые пихаются задачи.
  • Slym © (28.10.08 14:12) [9]
    K1LLADR1LLA ©   (28.10.08 13:59) [8]
    на вычисление регулярного выражения будут поступать огромные логи до 1ГБ

    ИЧЁ? стопудофф линейно без пулофф (при текущей реализации) быстрее буит...

    програм1

    делаем потоки по колву процессоров

    впотоке.еХекут
    {
    КоИнит;
    обж:=КреатОбжект('psirexuwz.wsc');
    дотехпорпокаживу дуит
    {
    задача:=ядро.дайзадачу
    обж.коитус(задача)
    ядро.яеёоткоитовал(задача)
    }

    КоДеИнит;
    }

  • Slym © (28.10.08 14:19) [10]
    смысла перевода непосредственного выполнения кода в теле потока в APC спящего потока я не вижу...
  • K1LLADR1LLA © (28.10.08 14:34) [11]
    мг, я буду иметь ввиду выше предложенное, хотя я уже мудохаюсь неделю ((=
    Если смысла не видно, то это ещё не значит, что смысла нет ((=
 
Конференция "WinAPI" » Windows Script Host + COM + ThreadPool [D7, WinXP]
Есть новые Нет новых   [134435   +33][b:0][p:0.003]