2013-04-04 7 views
1

J'ai une méthode qui recueille des actions d'information et écrire les résultats à la base de données, j'utilise Parallel.Foreach ce qui a augmenté les performances, surtout si la numérisation 100 ToParallel.ForEach dans la méthode récursive

Si je lance ce code dans ma section locale base de données, je n'ai pas de problèmes, mais sur la base de données de bac à sable j'ai eu des tonnes d'exceptions/InnerExceptions

code:

private static INodeCollection NodesLookUp(string path, int maximumLevel) 
     { 

      var shareCollectionNode = new ShareCollection(path); 
      shareCollectionNode.GetNodeProperties(); 
      shareCollectionNode.GetPermissionEntires(); 
      WriteNodeToDatabase(shareCollectionNode); // write collected infomation to database 
      if (maximumLevel <= 0 && _maximumSubLevels != -1) 
      { 
       return shareCollectionNode; 
      } 

      Parallel.ForEach(Directory.GetDirectories(shareCollectionNode.FullPath), directory => 
      { 
       try 
      { 
        lock (shareCollectionNode) 
        { 
         shareCollectionNode.AddNode(NodesLookUp(directory, maximumLevel - 1)); 
        } 

       } 
       catch (UnauthorizedAccessException unauthorizedAccessException) 
       { 
        lock (_shareIssues) 
        { 
         _shareIssues.Add(new ShareIssue(TraceStatu.UnauthorizedAccess, directory, 
        unauthorizedAccessException.Message, dfsId, currentLevel)); 
        } 

       } 

      }); 

      return shareCollectionNode; 
     } 

écriture à la base de données:

private static void WriteNodeToDatabase(ShareCollection shareCollection) 
    { 
     var nodeId = Persistence.UpsertShare(shareCollection); 
     var sharePermissions = new List<IPermissionRight>(); 
     foreach (var permissionEntry in shareCollection.PermissionEntries) 
     { 
      permissionEntry.NodeId = nodeId; 
      var permissionEntryId = Persistence.InsertPermissionEntry(permissionEntry); 
      permissionEntry.SetPermissions(permissionEntryId); 
      sharePermissions.AddRange(permissionEntry.Permissions); 
     } 
     Persistence.InsertPermissions(sharePermissions); 
    } 

Exceptions:

System.Data.SqlClient.SqlException (0x80131904): Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression. 
    at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) 
    at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) 
    at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() 
    at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) 
    at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) 
    at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) 
    at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) 
    at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe) 
    at System.Data.SqlClient.SqlCommand.ExecuteNonQuery() 

Si je supprime la Parallel.Foreach et de l'utilisation normale de la boucle i ont alors aucun problème à côté que l'application prend une éternité à courir.

+4

Veuillez formater le code d'une manière qui supprime ou au moins réduit le besoin de faire défiler horizontalement. –

+2

'Parallel.ForEach' qui se termine par un' lock'? – ken2k

+0

C'est ce que je n'aime pas à propos de la gestion des exceptions Pokemon: nous n'avons aucune idée d'où cette exception est lancée. Une idée quelle requête provoque cette erreur? – IdeaHat

Répondre

1

tout d'abord essayer de remplacer ce

lock (shareCollectionNode) 
{ 
    shareCollectionNode.AddNode(NodesLookUp(directory, maximumLevel - 1)); 
} 

avec ce

var node = NodesLookUp(directory, maximumLevel - 1); 
lock (shareCollectionNode) 
{ 
    shareCollectionNode.AddNode(node); 
} 

et même pour la deuxième serrure.

Bien que ce soit une meilleure façon d'obtenir ce que vous voulez en parallèle, il peut également être utile de reproduire localement les mêmes erreurs, car cela devrait augmenter l'activité de la base de données. Le problème réel repose sur des transactions DataBase - il semble que lors d'opérations de base de données simultanées, des résultats intermédiaires apparaissent dans des tables qui renvoient des données non valides; Je ne peux pas en dire plus tant que nous n'avons pas vu les requêtes et le schéma de la table.