O WebWorker calcula correspondências de expressões regulares lentas significativamente mais lentas (3x) - somente firefox


85

Primeiro, acabei de criar uma expressão regular que corresponderá a todos os caminhos de biblioteca externa exclusivos em uma lista de todos os arquivos de cabeçalho em um projeto. Eu fiz uma pergunta sobre como fazer essa regexp uma semana atrás.

Comecei a me intrometer para ver como ele se comportaria quando fosse assíncrono e quando se transformasse em um web worker. Por conveniência e confiabilidade, criei este arquivo universal que é executado em todos os três modos:

/** Will call result() callback with every match it founds. Asynchronous unless called 
 *  with interval = -1.
 *  Javadoc style comment for Arnold Rimmer and other Java programmers:
 *  
 * @param regex regular expression to match in string
 * @param string guess what
 * @param result callback function that accepts one parameter, string match
 * @param done callback on finish, has no parameters
 * @param interval delay (not actual interval) between finding matches. If -1, 
 *        function  will be blocking
 * @property working false if loop isn't running, otherwise contains timeout ID
 *           for use with clearTimeout
 * @property done copy of done parameter
 * @throws heavy boulders
**/
function processRegex(regex, string, result, done, interval) {
  var m;
  //Please tell me interpreter optimizes this
  interval = typeof interval!='number'?1:interval;
  //And this
  processRegex.done = done;
  while ((m = regex.exec(string))) {
    Array.prototype.splice.call(m,0,1);
    var path = m.join("");
    //It's good to keep in mind that result() slows down the process
    result(path);
    if (interval>=0) {
      processRegex.working = setTimeout(processRegex, 
                              interval, regex, string, 
                              result, done, interval);
      // Comment these out for maximum speed
      processRegex.progress = regex.lastIndex/string.length;
      console.log("Progress: "+Math.round(processRegex.progress*100)+"%");
      return;
    }
  }

  processRegex.working = false;
  processRegex.done = null;
  if (typeof done=="function")
    done();
}
processRegex.working = false; 

Eu criei um arquivo de teste, ao invés de colá-lo aqui, eu o carreguei em uma hospedagem web muito confiável: Demo - Dados de teste .

O que acho muito surpreendente é que haja uma diferença tão significativa entre o trabalhador da web e a execução do navegador do RegExp. Os resultados que obtive:

  • Mozilla Firefox
    • [WORKER]: Time elapsed:16.860s
    • [WORKER-SYNC]: Time elapsed:16.739s
    • [TIMEOUT]: Time elapsed:5.186s
    • [LOOP]: Time elapsed:5.028s

Você também pode ver que, com minha expressão regular específica, a diferença entre um loop síncrono e um assíncrono é insignificante. Tentei usar uma lista de correspondências em vez de uma expressão antecipada e os resultados mudaram muito. Aqui estão as alterações na função antiga:

function processRegexUnique(regex, string, result, done, interval) {
  var matchList = arguments[5]||[];
  ... same as before ...
  while ((m = regex.exec(string))) {
    ... same as before ...
    if (matchList.indexOf(path)==-1) {
      result(path);
      matchList.push(path);
    }
    if (interval>=0) {
      processRegex.working = setTimeout(processRegex, interval, 
                               regex, string, result, 
                               done, interval, matchList);
      ... same as before ...
    }
  }
  ... same as before ...
}

E os resultados:

  • Mozilla Firefox
    • [WORKER]: Time elapsed:0.062s
    • [WORKER-SYNC]: Time elapsed:0.023s
    • [TIMEOUT]: Time elapsed:12.250s (nota para mim mesmo: está ficando mais estranho a cada minuto)
    • [LOOP]: Time elapsed:0.006s

Alguém pode explicar essa diferença de velocidade?


6
Se você registrou um bug do Firefox para isso, pode adicionar o URL do bug à sua pergunta? E se você ainda não registrou um bug do Firefox para ele, espero que você possa considerar reservar um tempo para fazer isso.
sideshowbarker de

@sideshowbarker Pesquisei no Google onde relatar bugs do firefox e falhei. Então eu preenchi a reclamação " Não consigo encontrar onde relatar bugs " na entrada do Firefox (" Firefox me deixou triste. ") E desisti. Se você sabe onde relatar bugs (e é o procedimento de relatório real, não algum coletor de feedback do usuário), por favor me diga. Esta não seria a primeira vez que encontrei um problema que pudesse reproduzir e identificar de forma confiável como somente firefox.
Tomáš Zato - Reintegrar Monica

1
Sim, concordou que eles não deixam isso tão claro quanto poderia ser. De qualquer forma, para este bug em particular, use bugzilla.mozilla.org/… Isso o levantará contra o DOM: Workerscomponente bugzilla apropriado no Coreproduto Bugzilla apropriado .
sideshowbarker

1
Para tentar ajudar outras pessoas a evitar as mesmas frustrações que você encontrou ao tentar descobrir onde relatar bugs no mecanismo do navegador Firefox, criei stackoverflow.com/questions/33059442/… Se você acha que é útil ter essa informação registrada aqui em StackOverflow, por favor, considere votar a favor (caso contrário, pode haver o risco de ser excluído se outros downvoters arrogantes fecharem todas as coisas entrarem na onda).
sideshowbarker de

1
O padrão é lento propositalmente. Uma maneira muito mais eficiente de fazer é pular os lookaheads e usar o array de referência. Mas essa questão realmente não é sobre escrever um código ideal.
Tomáš Zato - Reintegrar Monica em

Respostas:


2

Após uma série de testes, confirmei que este é um problema do Mozilla Firefox (afeta todas as versões do Windows Desktop que experimentei). Com o Google Chrome, Opera, ou mesmo Firefox mobile, as correspondências regexp levam quase o mesmo, trabalhador ou não.

Se você precisa que este problema seja corrigido, certifique-se de votar no relatório de bug no bugzilla . Tentarei adicionar informações adicionais se algo mudar.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.