2017-07-28 20 views
5

Vì vậy, tôi đã làm tốt hơn phần đêm cố gắng tìm ra điều này.Làm thế nào để sử dụng chờ đợi trong một foreach song song?

Tôi đã may mắn được giới thiệu với parallel.foreach ngày hôm qua và nó hoạt động như tôi muốn nó làm ngoại trừ một chi tiết.

tôi có như sau:

 Parallel.ForEach(data, (d) => 
     { 
      try 
      { 
       MyMethod(d, measurements); 
      } 
      catch (Exception e) 
      { 
       // logg 
      } 

     }); 

Trong phương pháp "myMethod" Tôi có rất nhiều của logic đó được thực hiện và hầu hết là tốt nhưng tôi thực hiện cuộc gọi api nơi tôi lấy dữ liệu và tôi sử dụng công việc async cho điều này để có thể sử dụng "chờ đợi" để các mã để chờ đợi cho đến khi một phần cụ thể được thực hiện và sau đó chuyển sang:

private async void MyMethod(PimData pimData, IEnumerable<ProductMeasurements> measurements) 
    { 
     try 
     { 
      // alot of logic but most relevant part 

      await Task.WhenAll(ExecuteMeasurmentAndChartLogic(pimData.ProductNumber, entity)); 
      await Task.WhenAll(resourceImportManager.HandleEntityImageFiles(pimData.ProductType + pimData.ProductSize,SwepImageType.Png, ResourceFileTypes.ThreeD, entity, LinkTypeId.ProductResource)); 

      await Task.WhenAll(resourceImportManager.HandleEntityImageFiles(pimData.ProductSketch, SwepImageType.Png, ResourceFileTypes.Sketch, entity, LinkTypeId.ProductResource)); 

     } 
     catch (Exception e) 
     { 
      // logg 
     } 
    } 

vấn đề:

1 Đối với người mới bắt đầu vòng lặp kết thúc trước khi tất cả các mã xong

2 vấn đề thứ hai là tôi nhận được "nhiệm vụ đã bị hủy bỏ" trong rất nhiều api gọi

3 Và thứ ba như đã đề cập ở trên, mã không đợi cho mỗi phương thức để thực hiện đầy đủ.

Tôi không thể thực hiện mọi thứ trong phương thức ExecuteMeasurmentAndChartLogic() trước khi chuyển sang bước tiếp theo.

này mang lại cho tôi những vấn đề sau đây (các vấn đề khác):

Trong phương pháp này, tôi tạo ra một mục và thêm nó vào db, và mặt hàng này cần biết thêm rằng tôi nhận được từ một cuộc gọi api đó được thực hiện bên trong của ExecuteMeasurmentAndChartLogic() nhưng vấn đề là một số mục bị điên và phải chờ phần còn lại của dữ liệu mà không phải là những gì tôi mong muốn.

SIDE-LƯU Ý: Tôi nhận thức được rằng đóng thùng một mục và thêm vào db trước khi tất cả dữ liệu là không có thực hành tốt nhất nhưng tôi đang tích hợp theo hướng PIM và quá trình cho điều đó là tinh tế

tôi muốn một số luồng chạy nhưng đồng thời tôi muốn logic fuill thực hiện cho từng mục trước khi chuyển sang phương thức tiếp theo.

Làm rõ:

Một số mặt hàng chạy

Mỗi mục Handels ALL logic nó cần phải Handel trước khi chuyển sang phần tiếp theo của mã này, noramly làm điều này với chờ đợi.

Trong đoạn mã trên phương thức resourceImportManager() được thực hiện trước khi ExecuteMeasurmentAndChartLogic() kết thúc. đó là những gì tôi không muốn.

Thay vì song song.Foreach tôi đã sử dụng:

Task task1 = Task.Factory.StartNew(() => MyMethod(data, measurements)); 
    Task.WaitAll(task1); 

nhưng điều đó wasnt nhiều của một sự giúp đỡ

Khá mới này và havent đã có thể hiểu được tôi đang làm sai.

EDIT: cập nhật những vấn đề với

EDIT này: đây là cách ExecuteMeasurmentAndChartLogic() trông giống như:

public async Task ExecuteMeasurmentAndChartLogic(string productNumber, Entity entity) 
    { 
     try 
     { 
      GrafGeneratorManager grafManager = new GrafGeneratorManager(); 
      var graphMeasurmentList = await MeasurmentHandler.GetMeasurments(productNumber); 

      if (graphMeasurmentList.Count == 0) return; 

      var chart = await grafManager.GenerateChart(500, 950, SystemColors.Window, ChartColorPalette.EarthTones, 
       "legend", graphMeasurmentList); 

      await AddChartsAndAddToXpc(chart, entity, productNumber); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e); 
     } 

    } 

EDIT: Bối cảnh thế này: tôi thực hiện một cuộc gọi đến một api để nhận được rất nhiều dữ liệu. Đối với mỗi mục trong dữ liệu này, tôi cần thực hiện cuộc gọi api và nhận dữ liệu mà tôi áp dụng cho mục đó.

Sau khi đọc các nhận xét đã giúp tôi suy nghĩ theo cách khác. Tôi có lẽ có thể lặp qua tất cả các mục của tôi và làm logic nhỏ cho họ và thêm một url trong một danh sách nhiệm vụ và thực hiện một nhiệm vụ riêng biệt mà thực hiện từng cái một.

Vui lòng giữ cập nhật này

+0

Sử dụng các đại biểu gọi lại khi quá trình xử lý hoàn tất. – Ramankingdom

+0

Bất kỳ lý do cụ thể nào tại sao 'MyMethod' là một' async void' và không phải là một 'async Task'? – GWigWam

+0

@GWigWam không có lý do cụ thể, có ý nghĩa thay đổi nó, nhờ tôi nhắc tôi – ThunD3eR

Trả lời

7

Không sử dụng Parralel.ForEach. Đặt phương thức của bạn để trả lại Tác vụ thay vì hủy, thu thập tất cả nhiệm vụ và đợi chúng như sau:

Task.WaitAll(data.Select(d => MyMethod(d, someParam)).ToArray()); 
+0

cho tôi một kết quả tốt hơn cho đến nay nhưng tôi lo ngại, liệu nó có thực sự thực thi logic cho từng mục cùng một lúc không?Dường như đi rất nhiều chậm hơn vòng lặp tôi bắt đầu với – ThunD3eR

+0

Cách tôi thấy điều này là mỗi mục nhận nhiệm vụ nhưng mục hai chờ cho mục một thực thi, đó không phải là thứ tôi muốn, đưa tôi trở lại vòng lặp foreach bình thường – ThunD3eR

+0

Mã mà tôi đã cung cấp là Không đồng bộ và Song song. Nó có thể được thực thi trong một luồng nếu cấu hình Thread pool bị hỏng hoặc không có đủ luồng để capture. Hoặc có thể MyMethod có nút cổ chai và thực sự truy cập vào cùng một tài nguyên chặn. Tuy nhiên, nếu phương pháp này là hợp lệ, thì câu trả lời của tôi cũng hợp lệ. –

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