2013-06-08 11 views
5

Aşağıdaki kod var:.NET 4.0'daki devam görevinden görev istisnasını nasıl yaymalıyım?

innerExceptions = dbconnByServer 
    .AsParallel() 
    .WithDegreeOfParallelism(dbconnByServer.Count) 
    // A stream of groups of server connections proceeding in parallel per server 
    .Select(dbconns => dbconns.Select(dbconn => m_sqlUtilProvider.Get(dbconn))) 
    // A stream of groups of SqlUtil objects proceeding in parallel per server 
    .Select(sqlUtils => GetTaskException(sqlUtils 
     // Aggregate SqlUtil objects to form a single Task which runs the SQL asynchronously for the first SqlUtil, then upon completion 
     // for the next SqlUtil and so long until all the SqlUtil objects are processed asynchronously one after another. 
     .Aggregate<ISqlUtil, Task>(null, (res, sqlUtil) => 
     { 
      if (res == null) 
      { 
       return sqlUtil.ExecuteSqlAsync(SQL, parameters); 
      } 
      return res.ContinueWith(_ => sqlUtil.ExecuteSqlAsync(SQL, parameters)).Unwrap(); 
     }))) 
    .Where(e => e != null) 
    .ToList(); 

Nerede:

private static Exception GetTaskException(Task t) 
{ 
    try 
    { 
     t.Wait(); 
     return null; 
    } 
    catch (Exception exc) 
    { 
     return exc; 
    } 
} 

Ne bu kod yapar bazı bağlantıları bir DB sunucusuna ait olabilir db bağlantılarının çok sayıda genelinde belirli bir SQL deyimini yürütmek olduğunu diğerleri ise - diğerine vb.

kodu iki koşul tutun emin olur:

  1. ifadeleri mevcut DB sunucular arasında paralel olarak yürütülen SQL.
  2. Aynı DB sunucusunda, SQL deyimleri sıralı olarak değil, senkronize olarak çalıştırılır.

yürütme agregasyon sonunda tek Task, olacak bir DB sunucu başına db bağlantıları göz önüne alındığında, bunu takiben bir etkiye sahiptir:

  • db bağl SQL Yürütme 1
    • önceki tamamlanmasıyla, önceki tamamlanmasının ardından db baðlant 2
      • için SQL çalıştırmak db baðlant 3
      • için SQL çalıştırmak ... Önceki tamamlanmasının ardından
        • ,

    Sorunum şu anda istisnalar ilk db bağlantısı haricinde kaybı olmasıdır

db bağl N için SQL çalıştırmak. Biliyorum, _ argümanını incelemek ve bir şekilde devamı fonksiyonunda _.Exception özelliğini işlemek. Bunu yapmak için şık bir yol olup olmadığını merak ediyorum.

Herhangi bir fikrin var mı?

+0

Yani, aşağıdaki bağlantıları ile devam sonra bir şekilde saklamak istiyorum ve, sağ? – svick

+0

Ayrıca, eşzamanlı olarak "Wait()" sonucuna gidecekseniz, asenkron yöntem kullanmanın çok mantıklı olduğunu düşünmüyorum. – svick

cevap

1
  1. Senkronize olmayan yöntemler kullanacaksanız, tüm yöntem eşzamansız olmalı ve herhangi bir ileti dizisini engellememelidir.
  2. Bloke etmeyecekseniz, PLINQ kullanmanın pek bir nedeni yoktur, tek bir iş parçacığındaki süreklilikleri ayarlamak için yeterince hızlı olması gerekir.
  3. Bir istisna oluştuğunda devam etmek istiyorsanız, istisnaları kendiniz bir yere koymanız gerekir.
  4. Bir istisna koleksiyonuyla bunları fırlatmadan çalışmak konusunda kendimi rahatsız hissediyorum, ancak sanırım kısmen başarısız ve kısmen başarılı olabilecek bir işlem için sorun yok. Bunun üzerine

, bu iş için benim kod şuna benzer: Bir istisnası bazı bağlantı için olursa

public Task<IEnumerable<Exception>> ExecuteOnServersAsync(
    IList<IEnumerable<Connection>> dbConnByServer, 
    string sql, object parameters) 
{ 
    var tasks = new List<Task>(); 
    var exceptions = new ConcurrentQueue<Exception>(); 

    Action<Task> handleException = t => 
    { 
     if (t.IsFaulted) 
      exceptions.Enqueue(t.Exception); 
    }; 

    foreach (var dbConns in dbConnByServer) 
    { 
     Task task = null; 

     foreach (var dbConn in dbConns) 
     { 
      var sqlUtil = m_sqlUtilProvider.Get(dbConn); 

      if (task == null) 
      { 
       task = sqlUtil.ExecuteSqlAsync(sql, parameters); 
      } 
      else 
      { 
       task = task.ContinueWith(
        t => 
        { 
         handleException(t); 
         return sqlUtil.ExecuteSqlAsync(sql, parameters); 
        }).Unwrap(); 
      } 
     } 

     if (task != null) 
     { 
      task = task.ContinueWith(handleException); 
      tasks.Add(task); 
     } 
    } 

    return Task.Factory.ContinueWhenAll(
     tasks.ToArray(), _ => exceptions.AsEnumerable()); 
} 
+0

İstisnaları manuel olarak almayı düşündüm, sadece .NET'in bunu daha zarif yapmak için bazı araçları olabilir. Paralel yürütmeyi istiyorum çünkü istekler farklı DB sunucularına gider. Bununla birlikte, aynı DB sunucusunda, paralel bir değer yoktur, çünkü darboğaz disk IO'dur, bu da paralelleştirme için iyi bir aday değildir. – mark

+0

@mark Belki de noktayı özlediniz: kodum sürekliliği ve ardından (eşzamansız) ayarları tamamlamasını bekler. Bu, farklı sunuculara yapılan isteklerin * paralel olarak yürütüleceği anlamına gelir. – svick

+0

Ah, aptal ben. Tabi ki haklısın. Şimdi görebiliyorum. – mark

İlgili konular