2009-08-26 5 views
2

У меня есть поток, который подключается к двум сетевым ресурсам. Каждый раз, когда я пытаюсь подключиться, для ответа может потребоваться 10 секунд.Возвращаемые значения из двух длинных методов, используя потоки

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 
} 

Общее время двадцать секунд, но я бы очень хотел, чтобы это займет всего десять секунд - Запуск потоков каждый раз, когда я называю GetResource, получив ответ, а затем присоединиться каждый поток вернуть управление.

Каков наилучший способ для этого? Запустить два потока, каждый из которых возвращает значение? Анонимные методы, которые ссылаются на локальные переменные? Моя голова кружится. Код приветствуется.

ответ

4

Как насчет

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 

Короткие и сладкие.

+0

Мне тоже нравится. Я надеюсь, что сообщество поможет мне разобраться в лучшем подходе. – MedicineMan

+0

Из любопытства возникла причина, по которой вы выбрали фоновое представление обо всех инициализациях? Из того, что я вижу, теперь у вас будут накладные расходы на два фоновых потока, в то время как основной поток простаивает и ждет их завершения. –

+0

@ Jesse Squire: Это просто иллюстрация. Насколько мне известно, реальное приложение может иметь N ресурсов, где N> 2. В основном потоке могут быть другие вещи, которые он хочет сделать, прежде чем он будет 'Join'. –

1

Самый простой способ, что происходит со мной, чтобы сделать так, чтобы распараллелить один из вызовов на рабочем потоке, имея основной поток выполнения второй инициализации и ждать. Следующий snipet должен помочь проиллюстрировать:

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 

Для более детального обсуждения методов синхронизации потоков, вы можете посетить статью MSDN по теме: http://msdn.microsoft.com/en-us/library/ms173179.aspx

1

Это всегда забавные вопросы, чтобы обдумать, и, конечно же, есть несколько способов решить эту проблему.

Один из подходов, который сработал для меня, - это обеспечить метод обратного вызова, который каждый поток использует для возврата результатов и состояния. В следующем примере я использую Список, чтобы отслеживать выполнение потоков и помещать результаты в словарь.

с использованием системы; с использованием System.Collections.Generic; с использованием System.Linq; с использованием System.Text; с использованием System.Threading; с использованием System.Timers;

пространства имен ConsoleApplication1 { класс программы { статические словарь threadResults = новый словарь(); 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

кажется немного сложным.Может быть интересной альтернативой, если некоторые из других подходов не сработают – MedicineMan

Смежные вопросы