Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

159
Visualizações
¿Cómo sincronizar temporalmente en un bucle Parallel.ForEach?

Así que aquí hay una versión mínima de código que funciona, pero es ineficiente:

 Parallel.ForEach(list, x => { doThing1(x); }); Thing1Done = true; Parallel.ForEach(list, x => { doThing2(x); }); Thing2Done = true; Parallel.ForEach(list, x => { doThing3(x); }); Thing3Done = true;

Intuitivamente, me gustaría ejecutar las 3 "cosas" dentro del mismo bucle, pero deben poder sincronizarse temporalmente para actualizar la propiedad Thing*n*Done respectiva.

Pseudocódigo para esta idea de la siguiente manera:

 Parallel.ForEach(list, x => { doThing1(x); // wait for doThing1 to be completed for all other elements in list Thing1Done = true; doThing2(x); // wait for doThing2 to be completed for all other elements in list Thing2Done = true; doThing3(x); // wait for doThing3 to be completed for all other elements in list Thing3Done = true; });

Entonces, por ejemplo, es necesario que doThing1() finalice su ejecución para cada miembro de la list antes de que Thing1Done se establezca en verdadero. doThing2() solo puede comenzar después de que se haya configurado Thing1Done .

Cada paso individual no es demasiado costoso, y me preocupan los gastos generales relacionados con el enfoque ingenuo. ¿Cuál es la mejor manera de resolver esta tarea de manera eficiente , suponiendo que la sobrecarga involucrada en la inicialización de los subprocesos es mi mayor preocupación? También me gustaría evitar la espera ocupada (donde el hilo gira en un ciclo while sin hacer nada útil hasta que alguna bandera se establece en verdadero) si es posible.

Estoy dispuesto a escribir algo más general si la biblioteca paralela no puede hacer lo que quiero.

over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

Podría usar la primitiva de sincronización de subprocesos de Barrier :

 var barrier = new Barrier(list.Count); var options = new ParallelOptions() { MaxDegreeOfParallelism = list.Count, TaskScheduler = new ThreadPerTask() }; Parallel.ForEach(list, options, x => { doThing1(x); // wait for doThing1 to be completed for all other elements in list barrier.SignalAndWait(); doThing2(x); // wait for doThing2 to be completed for all other elements in list barrier.SignalAndWait(); doThing3(x); // wait for doThing3 to be completed for all other elements in list barrier.SignalAndWait(); });

El método SignalAndWait señala la finalización de un elemento y espera hasta que todos los elementos se hayan completado (hasta que la propiedad ParticipantsRemaining sea cero). Después de que se incremente la propiedad CurrentPhaseNumber , todos los subprocesos se desbloquean simultáneamente y son libres de correr hacia el siguiente hito.

Esta es una forma extremadamente ineficiente de procesar los elementos de la list , ya que requiere un subproceso dedicado por elemento. Necesitará un TaskScheduler personalizado para implementar esta configuración, como la que se muestra a continuación:

 public class ThreadPerTask : TaskScheduler { protected override void QueueTask(Task task) { new Thread(() => this.TryExecuteTask(task)) { IsBackground = true }.Start(); } protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) => false; protected override IEnumerable<Task> GetScheduledTasks() { yield break; } }

En mi humilde opinión, su primer enfoque, el que usa múltiples bucles Parallel.ForEach consecutivos, es la forma correcta de resolver este problema.

over 4 years ago · Santiago Trujillo Relatório

0

Como se mencionó en los comentarios, su segundo ejemplo tendrá una sobrecarga enorme, ya que requeriría usar un subproceso por elemento, y probablemente serán más subprocesos de los que están disponibles en el grupo de subprocesos, por lo que será necesario crear nuevos subprocesos, pero la tasa nueva los hilos que se crean son limitados. Así que esperaría un rendimiento terrible. Al menos suponiendo que tenga muchos elementos para procesar.

Si los requisitos son que doThing1 debe haberse completado para todos los elementos antes de que comience doThing2 , entonces no creo que pueda hacerlo mucho mejor que múltiples bucles paralelos secuenciales. No esperaría que la sobrecarga de este enfoque fuera tan mala, ya que utilizará el grupo de subprocesos en lugar de generar nuevos subprocesos.

Es posible que un particionador personalizado pueda ayudar, o dividir previamente su lista en fragmentos y procesar cada fragmento en paralelo. Por defecto, los bucles paralelos intentan dividir el trabajo en particiones e intentan adaptar el tamaño de estas particiones para equilibrar la sobrecarga con la utilización del proceso. Pero si tiene conocimiento previo del tipo de trabajo que debe hacer, probablemente pueda hacerlo mejor usted mismo. Como siempre cuando se habla de rendimiento, probablemente necesitará medir para ver qué alternativa es más rápida.

Si divide el trabajo en partes similares a la cantidad de procesadores, tal vez podría usar un modelo similar a su segundo ejemplo. Pero no estoy seguro de si tiene alguna ventaja real.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda