Domanda

Ho una domanda che ha molte casi. Ogni caso ha molti file TIF multipagina. Ho bisogno di convertire i file di TF fino file pdf. Dal momento che ci sono così tanti di file, ho pensato che avrei potuto infilare il processo di conversione. Attualmente sto limitando il processo di conversione dieci alla volta (vale a dire dieci gradini). Quando si completa conversione, un altro dovrebbe iniziare.

Questa è la configurazione attuale che sto utilizzando.

private void ConvertFiles()
{
  List<AutoResetEvent> semaphores = new List<AutoResetEvet>();
  foreach(String fileName in filesToConvert)
  {
    String file = fileName;

    if(semaphores.Count >= 10)
    {
      WaitHandle.WaitAny(semaphores.ToArray());
    }


    AutoResetEvent semaphore = new AutoResetEvent(false);
    semaphores.Add(semaphore);

    ThreadPool.QueueUserWorkItem(
      delegate
      { 
        Convert(file);
        semaphore.Set();
        semaphores.Remove(semaphore);
      }, null);
  }

  if(semaphores.Count > 0)
  {
    WaitHandle.WaitAll(semaphores.ToArray());
  }
}

Con questo, a volte si traduce in un'eccezione indicando il WaitHandle.WaitAll () o WaitHandle.WaitAny () parametri array non devono superare una lunghezza di 65. Che cosa sto facendo di sbagliato in questo approccio e come posso correggerlo?

È stato utile?

Soluzione

Ci sono alcuni problemi con quello che hai scritto.

1 °, non è thread-safe. Si dispone di più thread Aggiungere, rimuovere e in attesa sulla matrice di AutoResetEvents. I singoli elementi della lista sono accessibili su thread separati, ma tutto ciò che aggiunge, rimuove o assegni tutti gli elementi (come la chiamata WaitAny), necessità di farlo all'interno di una serratura.

2 °, non v'è alcuna garanzia che il codice elaborerà solo 10 file alla volta. Il codice tra quando è selezionata la dimensione della lista, e il punto in cui viene aggiunto un nuovo elemento è aperto per più thread per ottenere attraverso.

3 °, esiste il potenziale per le discussioni iniziate nel QueueUserWorkItem per convertire lo stesso file. Senza catturare il nome del file all'interno del ciclo, il filo che converte il file utilizzerà qualsiasi valore è nel nome del file quando si esegue, non tutto ciò che era nel nome del file quando hai chiamato QueueUserWorkItem.

In questo articolo CodeProject dovrebbe puntare nella giusta direzione per ciò che si sta cercando di fare: http://www.codeproject.com/KB/threads/SchedulingEngine.aspx

EDIT:

var semaphores = new List<AutoResetEvent>();
        foreach (String fileName in filesToConvert)
        {
            String file = fileName;
            AutoResetEvent[] array;
            lock (semaphores)
            {
                array = semaphores.ToArray();
            }
            if (array.Count() >= 10)
            {
                WaitHandle.WaitAny(array);
            }

            var semaphore = new AutoResetEvent(false);
            lock (semaphores)
            {
                semaphores.Add(semaphore);
            }
            ThreadPool.QueueUserWorkItem(
              delegate
              {
                  Convert(file);
                  lock (semaphores)
                  {
                      semaphores.Remove(semaphore);
                  }
                  semaphore.Set();
              }, null);
        }

Personalmente, non credo che farei in questo modo ... ma, lavorando con il codice che hai, questo dovrebbe funzionare.

Altri suggerimenti

Si sta utilizzando un vero e proprio semaforo ( System.Threading )? Quando si utilizza i semafori, in genere allocare le risorse max e Bloccherai in modo automatico (quando si aggiungono e rilascio). Si può andare con l'approccio WaitAny, ma sto ottenendo la sensazione che hai scelto la strada più difficile.

appare come è necessario rimuovere la maniglia della innescato la funzione WaitAny procedere

if(semaphores.Count >= 10)
{
  int index = WaitHandle.WaitAny(semaphores.ToArray());
  semaphores.RemoveAt(index);
}

Quindi, fondamentalmente vorrei togliere il:

semaphores.Remove(semaphore);

chiamata dal thread e utilizzare il sopra per l'evento segnalato e vedere se funziona.

Forse non si dovrebbe creare tanti eventi?

// input
var filesToConvert = new List<string>();
Action<string> Convert = Console.WriteLine;

// limit
const int MaxThreadsCount = 10;

var fileConverted = new AutoResetEvent(false);
long threadsCount = 0;

// start
foreach (var file in filesToConvert) {
    if (threadsCount++ > MaxThreadsCount) // reached max threads count 
        fileConverted.WaitOne();          // wait for one of started threads

    Interlocked.Increment(ref threadsCount);

    ThreadPool.QueueUserWorkItem(
        delegate {
            Convert(file);

            Interlocked.Decrement(ref threadsCount);
            fileConverted.Set();
        });
}

// wait
while (Interlocked.Read(ref threadsCount) > 0) // paranoia?
    fileConverted.WaitOne();
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top