异步MongoDB的并发变化(c#)

本文关键字:变化 并发 MongoDB 异步 | 更新日期: 2023-09-27 18:06:02

假设我有一个简单的对象:

class A
{
    int _id;
    int V1;
    int V2;
}

和MongoDB表与一堆这些:

现在,我定义了两个异步更新操作:
void UpdateV1(int id, int V)
{    
    var F = Builders<A>.Filter.Eq(_ => _._id, Id);
    var U = Builders<A>.Update.Set(_ => _.V1, V);
    Mongo.Driver.UpdateOneAsync(F, U);
}
void UpdateV2(int id, int V)
{    
    var F = Builders<A>.Filter.Eq(_ => _._id, Id);
    var U = Builders<A>.Update.Set(_ => _.V2, V);
    Mongo.Driver.UpdateOneAsync(F, U);
}

如果我运行以下命令:

UpdateV1(1, 10);

UpdateV2(1, 20);

在不同的线程上,但大致同时,发生了什么?

我得到:

  • 只有V1或V2改变的记录?
  • V1和V2都改变的记录?

我问这个问题的原因是我们有一个非常奇怪的错误,看起来第一个选项是正在发生的事情,但预期的结果显然是最后一个。

当我们做阻塞调用时,这些问题开始消失,但这也可能是一个副作用。

这是使用c#驱动程序,一切都是最新版本。

异步MongoDB的并发变化(c#)

我认为这不是你的查询问题,因为mongodb保证原子性和并发控制,看看这个链接了解更多。

我怀疑你的问题来自于如何安排任务。看看这个例子,如果您不等待Parallel.Invoke中的结果,您的查询将不会被执行,因为进程将在执行任务之前退出。所以如果你添加Console.ReadLine(),你的进程将被阻塞,允许mongo运行任务

namespace ConsoleApplication1
{
    class Program
    {
       static MongoClient mongoClient = new MongoClient();
        static IMongoDatabase databaseBase = mongoClient.GetDatabase("dbTest", null);
        static IMongoCollection<A> collection = databaseBase.GetCollection<A>("tests", null);
        static void Main(string[] args)
        {
            var a = new A
            {
                _id = 1,
                V1 = 0,
                V2 = 0
            };
            Parallel.Invoke( ()=> { var res=UpdateV1(1, 10).Result; },  ()=> { var res =  UpdateV2(1, 20).Result; });
            //Console.ReadLine(); 


        }
        static async  Task<long> UpdateV1(int id, int V)
        {
            var F = Builders<A>.Filter.Eq(a => a._id, id);
            var U = Builders<A>.Update.Set(a => a.V1, V);
            var result = await collection.UpdateOneAsync(F, U);
            return result.ModifiedCount;  
        }
        static async Task<long> UpdateV2(int id, int V)
        {
            var F = Builders<A>.Filter.Eq(_ => _._id, id);
            var U = Builders<A>.Update.Set(_ => _.V2, V);
            var result = await collection.UpdateOneAsync(F, U);
            return result.ModifiedCount;
        }

    }
    class A
    {
       public  int _id;
       public   int V1;
       public  int V2;
    }
}

也许你只能用UpdateOne代替UpdateOneAsync,看看会发生什么?