2010-05-27 41 views
9

Tôi muốn thực hiện 10 yêu cầu http không đồng bộ cùng một lúc và chỉ xử lý kết quả khi tất cả đã hoàn thành và trong một hàm gọi lại đơn. Tôi cũng không muốn chặn bất kỳ chủ đề bằng cách sử dụng WaitAll (đó là sự hiểu biết của tôi rằng WaitAll khối cho đến khi tất cả được hoàn thành). Tôi nghĩ rằng tôi muốn thực hiện một IAsyncResult tùy chỉnh mà sẽ xử lý nhiều cuộc gọi. Có phải tôi đang trên đường ray bên phải không? Có bất kỳ tài nguyên hay ví dụ nào ngoài đó mô tả việc xử lý này không?C# nhiều HttpNequest không đồng bộ với một cuộc gọi lại

+0

bối cảnh của hoạt động này là gì? Bên trong một trang web? – Keltex

+0

Loại điều này là rất gần tầm thường trong F #. Nó có thể là đáng giá để viết một mô-đun trong F # có thể được gọi từ mã C# ... –

+0

@Keltex nó sẽ là một phần của một ứng dụng web. – aepheus

Trả lời

4

Tôi thích giải pháp của Darin. Nhưng, nếu bạn muốn một cái gì đó truyền thống hơn, bạn có thể thử điều này.

Tôi chắc chắn sẽ sử dụng một loạt các xử lý chờ đợi và cơ chế WaitAll:

static void Main(string[] args) 
{ 

    WaitCallback del = state => 
    { 
     ManualResetEvent[] resetEvents = new ManualResetEvent[10]; 
     WebClient[] clients = new WebClient[10]; 

     Console.WriteLine("Starting requests"); 
     for (int index = 0; index < 10; index++) 
     { 
      resetEvents[index] = new ManualResetEvent(false); 
      clients[index] = new WebClient(); 

      clients[index].OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted); 

      clients[index].OpenReadAsync(new Uri(@"http:\\www.google.com"), resetEvents[index]); 
     } 

     bool succeeded = ManualResetEvent.WaitAll(resetEvents, 10000); 
     Complete(succeeded); 

     for (int index = 0; index < 10; index++) 
     { 
      resetEvents[index].Dispose(); 
      clients[index].Dispose(); 
     } 
    }; 

    ThreadPool.QueueUserWorkItem(del); 

    Console.WriteLine("Waiting..."); 
    Console.ReadKey(); 
} 

static void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) 
{ 
    // Do something with data...Then close the stream 
    e.Result.Close(); 

    ManualResetEvent readCompletedEvent = (ManualResetEvent)e.UserState; 
    readCompletedEvent.Set(); 
    Console.WriteLine("Received callback"); 
} 


static void Complete(bool succeeded) 
{ 
    if (succeeded) 
    { 
     Console.WriteLine("Yeah!"); 
    } 
    else 
    { 
     Console.WriteLine("Boohoo!"); 
    } 
} 
1

Tôi nghĩ bạn nên sử dụng phương pháp WaitAll. Nếu không, bạn sẽ xử lý 10 cuộc gọi lại IAsyncResult, và sử dụng một semaphore để xác định rằng tất cả 10 cuối cùng đã hoàn thành.

Hãy nhớ rằng WaitAll rất hiệu quả; nó không giống như sự silliness của việc có một sợi "ngủ". Khi một luồng ngủ, nó tiếp tục sử dụng thời gian xử lý. Khi một luồng là "không được lên lịch biểu" bởi vì nó nhấn một WaitAll, thì luồng không còn tiêu tốn bất kỳ thời gian xử lý nào nữa. Nó rất hiệu quả.

+0

Trong bối cảnh của hồ bơi thread IIS, nó vẫn còn sử dụng hoặc nó sẽ được đưa trở lại trong hồ bơi như nó là cho một cuộc gọi không đồng bộ? – aepheus

3

Trong .NET 4.0 có một đẹp song song Task library cho phép bạn làm những việc như:

using System; 
using System.Linq; 
using System.Net; 
using System.Threading.Tasks; 

class Program 
{ 
    public static void Main() 
    { 
     var urls = new[] { "http://www.google.com", "http://www.yahoo.com" }; 

     Task.Factory.ContinueWhenAll(
      urls.Select(url => Task.Factory.StartNew(u => 
      { 
       using (var client = new WebClient()) 
       { 
        return client.DownloadString((string)u); 
       } 
      }, url)).ToArray(), 
      tasks => 
      { 
       var results = tasks.Select(t => t.Result); 
       foreach (var html in results) 
       { 
        Console.WriteLine(html); 
       } 
     }); 
     Console.ReadLine(); 
    } 
} 

Như bạn có thể nhìn thấy cho từng url trong danh sách một nhiệm vụ khác nhau được bắt đầu và một lần tất cả các nhiệm vụ được hoàn thành gọi lại được gọi và thông qua kết quả của tất cả các nhiệm vụ.

+1

Thực ra, nó sẽ thực hiện cuộc gọi đồng bộ trong chuỗi công nhân riêng biệt. Để giải quyết vấn đề này, bạn nên sử dụng 'TaskFactory.FromAsync' +' client.BeginGetResponse'. Bằng cách này, các cổng hoàn thành I/O sẽ được sử dụng mà không chặn luồng. – VirusX

Các vấn đề liên quan