Uploaded image for project: 'C# Driver'
  1. C# Driver
  2. CSHARP-2497

CPU consumption high when using await in ForEachAsync

    • Type: Icon: Bug Bug
    • Resolution: Done
    • Priority: Icon: Critical - P2 Critical - P2
    • None
    • Affects Version/s: 2.7.3
    • Component/s: Performance
    • Labels:
      None

      I noticed this in our system. Our code was using a lot of CPU even when not "much" was going on. After some investigation i nailed it down to the short code snippets below.

      I'm using MongoDB C# driver 2.7.2.

      Both collections used have around 6k-10k documents in em.

      I see around 8-10% of CPU consumption when i use the code below:

      IMongoDatabase MyTenantMongoDatabase = MongoDB.MongoDatabase.Get(connectionString, "database");            
      FindOptions MyFindOptions = new FindOptions();
      MyFindOptions.NoCursorTimeout = true; //This can be a long running operation, so we don't want any timeouts!            
      await MyTenantMongoDatabase.GetCollection<BsonDocument>("collection")
                               .Find(new BsonDocument(), MyFindOptions)
                               .ForEachAsync(async document =>
                               {
                                   String MyLeftValue = document.GetValue("fieldX", String.Empty).AsString;
                                   String MyRightValue = document.GetValue("fieldY", String.Empty).AsString;                             
                                  FilterDefinition<BsonDocument> MyLeftObjectFilter = MyLeftObjectFilter = Builders<BsonDocument>.Filter.And( Builders<BsonDocument>.Filter.Eq("is_deleted", false),
                                                                  Builders<BsonDocument>.Filter.Eq("title", MyLeftValue));                             
                                  FilterDefinition<BsonDocument> MyRightObjectFilter = MyLeftObjectFilter = Builders<BsonDocument>.Filter.And( Builders<BsonDocument>.Filter.Eq("is_deleted", false),
                                                                  Builders<BsonDocument>.Filter.Eq("title", MyRightValue));                             
                                 FilterDefinition<BsonDocument> MyCountFilter = Builders<BsonDocument>.Filter.Or(MyLeftObjectFilter, MyRightObjectFilter);                            
                                 Int64 MyObjectNeededForRelationCount = await MyTenantMongoDatabase.GetCollection<BsonDocument>("othercollection")
                                       .CountDocumentsAsync(MyCountFilter);                         
                                });
      

       

      When i change it to the code snippet below i see around 0,5-1,5% of CPU consumption:

       IMongoDatabase MyTenantMongoDatabase = MongoDB.MongoDatabase.Get(connectionString, "database");            
      FindOptions MyFindOptions = new FindOptions();
                  
      MyFindOptions.NoCursorTimeout = true; //This can be a long running operation, so we don't want any timeouts!            
      await MyTenantMongoDatabase.GetCollection<BsonDocument>("collection")
                               .Find(new BsonDocument(), MyFindOptions)
                               .ForEachAsync(document =>
                               {
                                   String MyLeftValue = document.GetValue("fieldX", String.Empty).AsString;
                                   String MyRightValue = document.GetValue("fieldY", String.Empty).AsString;                             
                                  FilterDefinition<BsonDocument> MyLeftObjectFilter = MyLeftObjectFilter = Builders<BsonDocument>.Filter.And( Builders<BsonDocument>.Filter.Eq("is_deleted", false),
                                                                   Builders<BsonDocument>.Filter.Eq("title", MyLeftValue));                             
                                   FilterDefinition<BsonDocument> MyRightObjectFilter = MyLeftObjectFilter = Builders<BsonDocument>.Filter.And( Builders<BsonDocument>.Filter.Eq("is_deleted", false),
                                                                   Builders<BsonDocument>.Filter.Eq("title", MyRightValue));                             
                                   FilterDefinition<BsonDocument> MyCountFilter = Builders<BsonDocument>.Filter.Or(MyLeftObjectFilter, MyRightObjectFilter);                            
                                   Int64 MyObjectNeededForRelationCount = MyTenantMongoDatabase.GetCollection<BsonDocument>("othercollection")
                                       .CountDocuments(MyCountFilter);                         
                                });
      

       

      So the change is to not use the async & await on Count in the ForEachAsync. This is a simplified version, in my other code i see a drop from 15-24 => 0,5 - 2.

      If it's not clear please let me know!

            Assignee:
            wan.bachtiar@mongodb.com Wan Bachtiar
            Reporter:
            dennis@hoefakkr.nl Dennis Hoefakker
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: