1. 使用 readerwriterlockslim
.net 提供的高性能读写锁,支持以下模式:
读模式(read lock):允许多个线程同时读取。
写模式(write lock):独占锁,其他所有读写操作都会被阻塞。
using system.threading;
public class readwriteexample
{
private readonly readerwriterlockslim _lock = new readerwriterlockslim();
private int _shareddata = 0;
// 读操作
public int readdata()
{
_lock.enterreadlock();
try
{
return _shareddata;
}
finally
{
_lock.exitreadlock();
}
}
// 写操作
public void writedata(int value)
{
_lock.enterwritelock();
try
{
_shareddata = value;
}
finally
{
_lock.exitwritelock();
}
}
}优点:
细粒度控制读写操作。
支持递归锁和超时机制。
缺点:
需要手动管理锁的获取和释放。
2. 使用 concurrent 并发集合
.net 的 system.collections.concurrent 命名空间提供了线程安全的集合类,内部已实现读写分离逻辑:
concurrentdictionary<tkey, tvalue>concurrentqueue<t>concurrentbag<t>
using system.collections.concurrent;
public class concurrentexample
{
private readonly concurrentdictionary<string, int> _data = new();
// 读操作(无锁)
public int getvalue(string key)
{
return _data.trygetvalue(key, out int value) ? value : -1;
}
// 写操作(内部使用细粒度锁)
public void updatevalue(string key, int value)
{
_data.addorupdate(key, value, (k, oldvalue) => value);
}
}优点:
开箱即用,无需手动管理锁。
高性能,适合高频读写场景。
缺点:
灵活性较低,仅适用于预定义的集合类型。
3. 基于 volatile 和内存屏障(memory barrier)
适用于简单变量的读写分离,通过 volatile 关键字确保内存可见性:
public class volatileexample
{
private volatile bool _flag = false;
private int _data = 0;
// 读操作(无锁)
public int readdata()
{
if (_flag)
return _data;
return -1;
}
// 写操作(需要同步)
public void writedata(int value)
{
interlocked.exchange(ref _data, value); // 原子写入
volatile.write(ref _flag, true); // 确保写入对其他线程可见
}
}优点:
轻量级,适合简单场景。
无锁读操作。
缺点:
仅适用于简单类型(如
int、bool)。需要手动处理内存可见性。
4. 数据库读写分离
在数据库层面实现读写分离(如主从架构),c# 代码通过不同连接字符串路由请求:
public class databaserouter
{
private static readonly string readconnectionstring = "server=readserver;...";
private static readonly string writeconnectionstring = "server=writeserver;...";
public idbconnection getreadconnection() =>
new sqlconnection(readconnectionstring);
public idbconnection getwriteconnection() =>
new sqlconnection(writeconnectionstring);
}
// 使用示例
using (var readconn = databaserouter.getreadconnection())
{
// 执行查询操作
}
using (var writeconn = databaserouter.getwriteconnection())
{
// 执行更新操作
}优点:
直接利用数据库主从复制特性。
减轻主库压力。
缺点:
需要数据库支持主从同步。
可能存在数据同步延迟。
5. 基于不可变数据(immutable data)
通过每次修改生成新对象实现无锁读取(如使用 immutablelist<t> 或自定义不可变类型):
using system.collections.immutable;
public class immutableexample
{
private immutablelist<int> _data = immutablelist<int>.empty;
// 读操作(无锁)
public int getitem(int index)
{
return _data[index];
}
// 写操作(原子替换)
public void additem(int item)
{
immutableinterlocked.update(ref _data, list => list.add(item));
}
}优点:
完全无锁读取。
天然线程安全。
缺点:
频繁修改可能产生内存压力。
选择策略
| 场景 | 推荐方案 |
|---|---|
| 细粒度代码级读写控制 | readerwriterlockslim |
| 高频并发集合操作 | concurrentdictionary 等并发集合 |
| 简单变量的读写 | volatile + interlocked |
| 数据库访问分离 | 主从架构 + 连接路由 |
| 高频读、低频写 | 不可变数据(如 immutablelist) |
注意事项
避免死锁:确保锁的获取和释放成对出现(用
try-finally块)。性能权衡:读写锁适合读多写少场景,写频繁时可能不如普通锁高效。
数据一致性:数据库读写分离时需处理主从同步延迟问题。
到此这篇关于c#实现读写分离的五种方法小结的文章就介绍到这了,更多相关c#读写分离内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论