2009-08-26 5 views
2

J'ai un thread qui se connecte à deux ressources réseau. Chaque fois que je tente une connexion, la réponse peut prendre 10 secondes.Renvoie les valeurs de deux méthodes longues, en utilisant des threads

void MyThread() 
{ 
    //this takes ten seconds 
    Resource r1 = MySystem.GetResource(ipAddress1); 

    //this takes ten seconds 
    Resource r2 = MySystem.GetResource(ipAddress2); 

    //do stuff with ep1 and ep2 
} 

Temps total est de vingt secondes, mais je voudrais vraiment à prendre seulement dix secondes - fils lancement chaque fois que j'appelle GetResource, recevoir une réponse, puis se joindre à chaque thread pour rendre le contrôle.

Quelle est la meilleure façon de faire cela? Lancez deux threads qui retournent chacun une valeur? Des méthodes anonymes qui prennent des références aux variables locales? J'ai la tête qui tourne. Le code est apprécié.

Répondre

4

Que diriez-vous

Resource r1 = null; // need to initialize, else compiler complains 
Resource r2 = null; 

ThreadStart ts1 = delegate { 
    r1 = MySystem.GetResource(ipAddress1); 
}; 
ThreadStart ts2 = delegate { 
    r2 = MySystem.GetResource(ipAddress2); 
}; 
Thread t1 = new Thread(ts1); 
Thread t2 = new Thread(ts2); 
t1.Start(); 
t2.Start(); 
// do some useful work here, while the threads do their thing... 
t1.Join(); 
t2.Join(); 
// r1, r2 now setup 

Court et doux.

+0

J'aime aussi celui-ci. J'espère que la communauté peut m'aider à trouver la meilleure approche – MedicineMan

+0

Par curiosité, y avait-il une raison pour laquelle vous avez choisi de mettre en arrière les deux initialisations? D'après ce que je peux voir, vous aurez maintenant la surcharge de deux threads d'arrière-plan, tandis que le thread principal est inactif et attend qu'ils finissent. –

+0

@Jesse Squire: C'est juste une illustration. Pour tout ce que je sais, l'application réelle pourrait avoir N ressources où N> 2. Le thread principal peut avoir d'autres choses qu'il veut faire avant de faire le 'Join's. –

1

La façon la plus simple qui se produit à moi de le faire est de paralléliser un des appels sur un thread de travail tout en ayant le thread principal effectuer la seconde initialisation et attendez. La snipet suivante devrait aider à illustrer:

ManualResetEvent r1Handle = new ManualResetEvent(false); 
Resource   r1  = null; 
Resource   r2  = null; 

// Make the threadpool responsible for populating the 
// first resource. 

ThreadPool.QueueUserWorkItem((state) => 
{ 
    r1 = MySystem.GetResource(ipAddress1); 

    // Set the wait handle to signal the main thread that 
    // the work is complete. 

    r1Handle.Set(); 
}); 

// Populate the second resource. 

r2 = MySystem.GetResource(ipAddress2); 

// Wait for the threadpool worker to finish. 

r1Handle.WaitOne(); 

// ... Do more stuff 

Pour une discussion plus détaillée des techniques de synchronisation de fil, vous voudrez peut-être consulter l'article MSDN sur le sujet: http://msdn.microsoft.com/en-us/library/ms173179.aspx

1

Ce sont toujours des questions amusantes à méditer, et bien sûr il y a plusieurs façons de le résoudre.

Une approche qui a bien fonctionné pour moi est de fournir une méthode de rappel que chaque thread utilise pour renvoyer les résultats et l'état. Dans l'exemple suivant, j'utilise une liste pour suivre les threads en cours d'exécution et placer les résultats dans un dictionnaire.

en utilisant System; en utilisant System.Collections.Generic; en utilisant System.Linq; en utilisant System.Text; en utilisant System.Threading; en utilisant System.Timers;

espace de noms ConsoleApplication1 { programme classe { threadResults Dictionnaire statique = new Dictionary(); static int threadMax = 2;

static void Main(string[] args) 
    { 
     List<Thread> runningThreads = new List<Thread>(); 
     for (int i = 0; i < threadMax; i++) 
     { 
      Worker worker = new Worker(); 
      worker.Callback = new Worker.CallbackDelegate(ThreadDone); 
      Thread workerThread = new Thread(worker.DoSomething); 
      workerThread.IsBackground = true; 
      runningThreads.Add(workerThread); 
      workerThread.Start(); 
     } 

     foreach (Thread thread in runningThreads) thread.Join(); 
    } 

    public static void ThreadDone(int threadIdArg, object resultsArg) 
    { 
     threadResults[threadIdArg] = resultsArg; 
    } 
} 


class Worker 
{ 
    public delegate void CallbackDelegate(int threadIdArg, object resultArg); 
    public CallbackDelegate Callback { get; set; } 
    public void DoSomething() 
    { 
     // do your thing and put it into results 
     object results = new object(); 
     int myThreadId = Thread.CurrentThread.ManagedThreadId; 
     Callback(myThreadId, results); 
    } 
} 

}

+0

semble un peu compliqué.Peut être une alternative intéressante si certaines des autres approches ne fonctionnent pas – MedicineMan

Questions connexes