Problema de velocidad de subprocesos múltiples

Agregué una parte de subprocesos múltiples a mi código.

 public class ThreadClassSeqGroups
    {
        public Dictionary<string, string> seqGroup;
        public Dictionary<string, List<SearchAlgorithm.CandidateStr>> completeModels;
        public Dictionary<string, List<SearchAlgorithm.CandidateStr>> partialModels;
        private Thread nativeThread;

        public ThreadClassSeqGroups(Dictionary<string, string> seqs)
        {
            seqGroup = seqs;
            completeModels  = new Dictionary<string, List<SearchAlgorithm.CandidateStr>>();
            partialModels   = new Dictionary<string, List<SearchAlgorithm.CandidateStr>>();
        }

        public void Run(DescrStrDetail dsd, DescrStrDetail.SortUnit primarySeedSu,
            List<ushort> secondarySeedOrder, double partialCutoff)
        {
            nativeThread = new Thread(() => this._run(dsd, primarySeedSu, secondarySeedOrder, partialCutoff));
            nativeThread.Priority = ThreadPriority.Highest;
            nativeThread.Start();
        }

        public void _run(DescrStrDetail dsd, DescrStrDetail.SortUnit primarySeedSu,
            List<ushort> secondarySeedOrder, double partialCutoff)
        {
            int groupSize = this.seqGroup.Count;
            int seqCount = 0;
            foreach (KeyValuePair<string, string> p in seqGroup)
            {
                Console.WriteLine("ThreadID {0} (priority:{1}):\t#{2}/{3} SeqName: {4}",
                    nativeThread.ManagedThreadId, nativeThread.Priority.ToString(), ++seqCount, groupSize, p.Key);
                List<SearchAlgorithm.CandidateStr> tmpCompleteModels, tmpPartialModels;
                SearchAlgorithm.SearchInBothDirections(
                        p.Value.ToUpper().Replace('T', 'U'), dsd, primarySeedSu, secondarySeedOrder, partialCutoff,
                        out tmpCompleteModels, out tmpPartialModels);
                completeModels.Add(p.Key, tmpCompleteModels);
                partialModels.Add(p.Key, tmpPartialModels);
            }
        }

        public void Join()
        {
            nativeThread.Join();
        }

    }

class Program
{
    public static int _paramSeqGroupSize = 2000;
    static void Main(Dictionary<string, string> rawSeqs)
    {
        // Split the whole rawSeqs (Dict<name, seq>) into several groups
        Dictionary<string, string>[] rawSeqGroups = SplitSeqFasta(rawSeqs, _paramSeqGroupSize);


        // Create a thread for each seqGroup and run
        var threadSeqGroups = new MultiThreading.ThreadClassSeqGroups[rawSeqGroups.Length];
        for (int i = 0; i < rawSeqGroups.Length; i++)
        {
            threadSeqGroups[i] = new MultiThreading.ThreadClassSeqGroups(rawSeqGroups[i]);
            //threadSeqGroups[i].SetPriority();
            threadSeqGroups[i].Run(dsd, primarySeedSu, secondarySeedOrder, _paramPartialCutoff);
        }

        // Merge results from threads after the thread finish
        var allCompleteModels   = new Dictionary<string, List<SearchAlgorithm.CandidateStr>>();
        var allPartialModels    = new Dictionary<string, List<SearchAlgorithm.CandidateStr>>();
        foreach (MultiThreading.ThreadClassSeqGroups t in threadSeqGroups)
        {
            t.Join();
            foreach (string name in t.completeModels.Keys)
            {
                allCompleteModels.Add(name, t.completeModels[name]);
            }
            foreach (string name in t.partialModels.Keys)
            {
                allPartialModels.Add(name, t.partialModels[name]);
            }
        }
    }
}

Sin embargo, la velocidad con múltiples subprocesos es mucho más lenta que con un solo subproceso, y la carga de la CPU es generalmente <10%.

Por ejemplo:

El archivo de entrada contiene 2500 cadenas.

_paramGroupSize = 3000, subproceso principal + 1 subproceso de cálculo cuesta 200 segundos

_paramGroupSize = 400, subproceso principal + 7 subprocesos de cálculo cuestan mucho más tiempo (lo eliminé después de más de 10 minutos de ejecución).

¿Hay algún problema con mi implementación? ¿Cómo acelerarlo?

Gracias.

preguntado el 27 de julio de 12 a las 16:07

¿Qué SearchAlgorithm.SearchInBothDirections ¿hacer? -

Use un generador de perfiles como DotTrace, le mostrará dónde se consume el tiempo. -

@ Bryan: SearchAlgorithm.SearchInBothDirections está realizando una búsqueda intensiva en una cadena dada, devuelve dos listas de candidatosStr como parámetros -

La razón por la que probablemente sea más lento es que tiene más trabajo que hacer que núcleos de CPU que puedan manejarlo. Sus subprocesos pasan más tiempo cambiando de contexto que haciendo el trabajo real. Intente usar menos subprocesos: el hecho de que agregue más subprocesos no significa que será más eficiente. -

3 Respuestas

Me parece que está intentando procesar un archivo en paralelo con varios subprocesos. Esta es una mala idea, suponiendo que tiene un solo disco mecánico.

Básicamente, el cabezal del disco necesita buscar la siguiente ubicación de lectura para cada solicitud de lectura. Esta es una operación costosa y dado que varios subprocesos emiten comandos de lectura, significa que la cabeza rebota cuando cada subproceso tiene su turno para ejecutarse. Esto reducirá drásticamente el rendimiento en comparación con el caso en el que un solo subproceso realiza la lectura.

Respondido 27 Jul 12, 19:07

¿Cuál era el código antes de los subprocesos múltiples? Es difícil saber qué está haciendo este código, y gran parte del código "funcional" parece estar oculto en su algoritmo de búsqueda. Sin embargo, algunos pensamientos:

  1. Menciona un "archivo de entrada", pero esto no se muestra claramente en el código: si el acceso a su archivo está siendo subprocesado, esto no aumentará el rendimiento ya que el acceso al archivo será el cuello de botella.
  2. La creación de más subprocesos que los núcleos de CPU que tiene reducirá en última instancia el rendimiento (a menos que cada subproceso esté bloqueado esperando en diferentes recursos). En su caso, sugeriría que 8 hilos en total son demasiados.
  3. Parece que se puede acceder a una gran cantidad de datos (memoria) a través de su clase DescrStrDetail que se pasa de variable dsd en tu Main método para cada subproceso secundario. Sin embargo, falta la declaración de esta variable, por lo que se desconoce su uso/implementación. Si esta variable tiene bloqueos que impiden que varios subprocesos accedan al mismo tiempo, es posible que sus múltiples subprocesos se bloqueen entre sí estos datos, lo que ralentizará aún más el rendimiento.

Respondido 27 Jul 12, 16:07

Cuando se ejecutan subprocesos, se les da tiempo en un procesador específico. si hay más subprocesos que procesadores, el contexto del sistema cambia entre subprocesos para que todos los subprocesos activos tengan tiempo de procesarse. El cambio de contexto es muy caro. Si tiene más subprocesos que procesadores, la mayor parte del tiempo de la CPU puede ocuparse mediante el cambio de contexto y hacer que se vea una solución de un solo subproceso. Más rápida que una solución multihilo.

Su ejemplo muestra el inicio de un número indeterminado de subprocesos. Si SplitSeqFasta devuelve más entradas que núcleos, creará más hilos y núcleos e introducirá muchos cambios de contexto.

Le sugiero que reduzca la cantidad de subprocesos manualmente, o use algo como la biblioteca paralela de subprocesos y la clase Parallel para que se reduzca automáticamente por usted.

Respondido 27 Jul 12, 17:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.