Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

507
Views
C# Parallel.ForEach y Task.WhenAll a veces devuelven menos valores de los supuestos

Tengo esto:

 Parallel.ForEach(numbers, (number) => { var value = Regex.Replace(number, @"\s+", "%20"); tasks.Add(client.GetAsync(url + value)); }); await Task.WhenAll(tasks).ConfigureAwait(false); foreach (var task in tasks) { ... }

A veces, devuelve menos tareas cuando se llega a foreach (var tarea en tareas), pero después de algunas solicitudes, comienza a devolver todas las tareas.

Cambié ConfigureAwait a verdadero y todavía a veces devuelve menos tareas.

Por cierto, estoy usando Parallel.ForEach porque cada cliente.GetAsync (url + valor) es una solicitud a una API externa con la particularidad de que su SLA de latencia es inferior a 1 s para el 99% de sus solicitudes

¿Pueden explicarme por qué a veces devuelve menos tareas?

¿Y hay alguna forma de garantizar la devolución siempre de todas las tareas?

Gracias

over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

¿Y hay alguna forma de garantizar la devolución siempre de todas las tareas?

Varias personas en los comentarios señalan que solo debe hacer esto, suponiendo que los numbers no son una lista segura para subprocesos:

 foreach(var number in numbers) { var value = Regex.Replace(number, @"\s+", "%20"); tasks.Add(client.GetAsync(url + value)); } await Task.WhenAll(tasks).ConfigureAwait(false); foreach (var task in tasks) { ... }

No parece haber ningún beneficio considerable en paralelizar la creación de las tareas que realizan la descarga; esto sucede muy rápido. La espera a que se completen las descargas se realiza en el WhenAll

PD; hay una variedad de formas más complicadas de escapar datos para una URL, pero si está buscando específicamente convertir cualquier tipo de espacio en blanco a% 20, supongo que tiene sentido hacerlo con expresiones regulares.

Editar; usted preguntó cuándo usar un Parallel ForEach, y voy a decir "no lo haga, en general, porque debe tener más cuidado con los contextos en los que lo usa", pero si hizo Parallel.ForEach hacer más trabajo sincrónico, podría tener sentido:

 Parallel.ForEach(numbers, number => { var value = Regex.Replace(number, @"\s+", "%20"); var r = client.Get(url + value)); //do something meaningful with r here, ie whatever ... is in your foreach (var task in tasks) });

pero tenga en cuenta que si está realizando actualizaciones de algo compartido, con fines de coordinación, desde dentro del cuerpo, entonces deberá ser seguro para subprocesos

over 4 years ago · Santiago Trujillo Report

0

No lo ha mostrado, por lo que solo podemos adivinar, pero asumo que tasks son una List<> . Este tipo de colección no es seguro para subprocesos ; es probable que su ciclo paralelo "sobrescriba" valores. Realice un bloqueo manual de su lista o cambie a una colección segura para subprocesos, como ConcurrentQueue<>

 var tasks = new ConcurrentQueue<Task<string>>(); Parallel.ForEach(numbers, number => { var value = Regex.Replace(number, @"\s+", "%20"); tasks.Enqueue(client.GetAsync(url + value)); }); await Task.WhenAll(tasks.ToArray()).ConfigureAwait(false); foreach (var task in tasks) { // whatever }

Dicho esto, su uso de Parallel.ForEach es bastante sospechoso. No está realizando nada de importancia real dentro del bucle. El uso de Parallel , especialmente con el bloqueo adecuado, probablemente tenga una sobrecarga más alta que anule cualquier ganancia potencial que afirma observar o que se obtiene al paralelizar las llamadas Regex . Convertiría esto en un bucle foreach normal y precompilaría Regex para compensar (algo de) su sobrecarga:

 // in class private static readonly Regex SpaceRegex = new Regex(@"\s+", RegexOptions.Compiled); // in method var tasks = new List<Task<string>>(); foreach (var number in numbers) { var value = SpaceRegex.Replace(number, "%20"); tasks.Add(client.GetAsync(url + value)); } await Task.WhenAll(tasks).ConfigureAwait(false); foreach (var task in tasks) { // whatever }

Alternativamente, no use una expresión regular en absoluto. Use un mecanismo de escape Uri adecuado que tendrá el beneficio adicional de arreglar más que solo espacios:

 var value = Uri.EscapeDataString(number); // or var fullUri = Uri.EscapeUriString(url + number);

Tenga en cuenta que hay dos métodos diferentes allí. El adecuado para usar depende de los valores de url y number . También hay otros mecanismos como el método HttpUtility.UrlEncode ... pero creo que estos son los preferidos.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!