C# 在存储库中锁定单个会话是否线程安全?(NHibernate)
我读过很多帖子,说多线程应用程序必须为每个线程使用单独的会话。也许我不明白锁定是如何工作的,但是如果我在所有存储库方法中对会话设置了锁定,这难道不会使单个静态会话线程安全吗 比如: 编辑: 请考虑我所写的应用程序的上下文/类型:C# 在存储库中锁定单个会话是否线程安全?(NHibernate),c#,.net,multithreading,nhibernate,session,C#,.net,Multithreading,Nhibernate,Session,我读过很多帖子,说多线程应用程序必须为每个线程使用单独的会话。也许我不明白锁定是如何工作的,但是如果我在所有存储库方法中对会话设置了锁定,这难道不会使单个静态会话线程安全吗 比如: 编辑: 请考虑我所写的应用程序的上下文/类型: 不是多用户的,也不是典型的用户交互,而是一个自动运行的机器人,对远程事件(如财务数据和订单更新)做出反应,并在此基础上执行任务和保存。这会间歇性地创建每秒最多10次存储的群集。通常,每次都需要保存相同的对象图。此外,在启动时,程序会将完整的数据库加载到实体对象图中。所以
不是多用户的,也不是典型的用户交互,而是一个自动运行的机器人,对远程事件(如财务数据和订单更新)做出反应,并在此基础上执行任务和保存。这会间歇性地创建每秒最多10次存储的群集。通常,每次都需要保存相同的对象图。此外,在启动时,程序会将完整的数据库加载到实体对象图中。所以它基本上只读取一次,然后在运行时执行SaveOrUpdates 至少有两个缺点:
我相信人们会增加其他缺点。至少有两个缺点:
我相信人们会增加其他缺点。鉴于应用程序通常编辑同一个对象图,也许有一个线程专门用于将这些编辑应用于对象图,然后将其保存到数据库,或者有一个线程池为公共编辑队列提供服务,这会更有意义,每个线程都有自己的(专用)会话,不需要锁定。查找生产者/消费者队列(要开始,请查看) 大概是这样的:
[Producer Threads]
Edit Event -\ [Database Servicer Thread]
Edit Event ------> Queue -> Dequeue and Apply to Session -> Database
Edit Event -/
我认为BlockingCollection
将是这样一个实现的良好起点
下面是一个粗略的例子(请注意,这显然未经测试):
//假设您的工作队列定义为
public static BlockingCollection myWorkQueue=new BlockingCollection();
//您的eventargs看起来像这样
公共类MyObjectUpdatedEventArgs:EventArgs{
公共MyObject MyObject{get;set;}
}
//和一个事件处理程序
公共MyObjectWasChangedEventHandler(对象发送器,MyObjectUpdatedEventArgs e){
添加(s=>SaveOrUpdate(e.MyObject));
}
//然后,处理这些项的常量循环中的线程可以工作:
public void ProcessWorkQueue(){
var mySession=mySessionFactory.CreateSession();
while(true){
var nextWork=myWorkQueue.Take();
下一网络(我的会话);
}
}
//并运行上述程序:
var dbUpdateThread=新线程(ProcessWorkQueue);
dbUpdateThread.IsBackground=true;
dbUpdateThread.Start();
鉴于应用程序通常编辑同一个对象图,可能更合理的做法是让一个线程专用于将这些编辑应用于对象图,然后将其保存到数据库,或者让一个线程池为公共编辑队列提供服务,其中每个线程都有自己的(专用)不需要锁定的会话。查找生产者/消费者队列(要开始,请查看)
大概是这样的:
[Producer Threads]
Edit Event -\ [Database Servicer Thread]
Edit Event ------> Queue -> Dequeue and Apply to Session -> Database
Edit Event -/
我认为BlockingCollection
将是这样一个实现的良好起点
下面是一个粗略的例子(请注意,这显然未经测试):
//假设您的工作队列定义为
public static BlockingCollection myWorkQueue=new BlockingCollection();
//您的eventargs看起来像这样
公共类MyObjectUpdatedEventArgs:EventArgs{
公共MyObject MyObject{get;set;}
}
//和一个事件处理程序
公共MyObjectWasChangedEventHandler(对象发送器,MyObjectUpdatedEventArgs e){
添加(s=>SaveOrUpdate(e.MyObject));
}
//然后,处理这些项的常量循环中的线程可以工作:
public void ProcessWorkQueue(){
var mySession=mySessionFactory.CreateSession();
while(true){
var nextWork=myWorkQueue.Take();
下一网络(我的会话);
}
}
//并运行上述程序:
var dbUpdateThread=新线程(ProcessWorkQueue);
dbUpdateThread.IsBackground=true;
dbUpdateThread.Start();
谢谢!请看我的编辑。根据我的观察,创建会话需要0.5秒(使用SQLite),因此使用单个会话是我提高性能的尝试。无论如何,我都会将整个数据库加载到内存中。创建一个会话大约需要20毫秒。也许您不是在创建会话,而是在重新创建ISessionFactory(当然这不是必需的)?我必须检查一下,它是否应该那么快。。但我也相信多个线程会话
// Assuming you have a work queue defined as
public static BlockingCollection<Action<Session>> myWorkQueue = new BlockingCollection<Action<Session>>();
// and your eventargs looks something like this
public class MyObjectUpdatedEventArgs : EventArgs {
public MyObject MyObject { get; set; }
}
// And one of your event handlers
public MyObjectWasChangedEventHandler(object sender, MyObjectUpdatedEventArgs e) {
myWorkQueue.Add(s=>SaveOrUpdate(e.MyObject));
}
// Then a thread in a constant loop processing these items could work:
public void ProcessWorkQueue() {
var mySession = mySessionFactory.CreateSession();
while (true) {
var nextWork = myWorkQueue.Take();
nextWork(mySession);
}
}
// And to run the above:
var dbUpdateThread = new Thread(ProcessWorkQueue);
dbUpdateThread.IsBackground = true;
dbUpdateThread.Start();