我有一个我用c#编写的服务,它接受来自多个来源的请求。为每个请求分配一个ID(简单int),该ID对于每个请求都会递增。目前,递增的计数器变量是一个全局变量(很好),我按以下方式递增它(为了我的理解和测试是线程安全的):
Interlocked.Increment(ref _currentId);
有时可能会重新启动服务,在这种情况下,变量会重置为0.但重启后,我实际上需要分配的最后一个ID。
我想我应该做的是每次变量递增时将其写入文件 - 确保文件始终包含最新的id。
如何在线程安全可靠的情况下(文件始终包含最新的id)方式实现这样的事情?
此外,性能非常重要,所以我不想在IO操作上花费太多时间(我可能会将文件写入操作放在线程/任务中) - 你有什么建议?
由于
答案 0 :(得分:0)
嗯,实现这一目标的最简单方法是使用lock
块:
private static object syncObj = new object();
private static int counter = 0;
// Returns the incremented value
private static int Increment()
{
lock (this.syncObj)
{
int currentCount = counter;
currentCount++;
// Write currentCount to a file here
try
{
// TODO -> write operation
// ...
counter = currentCount;
return currentCount;
}
catch (Exception)
{
// Do catch the exception in case the I/O operation failed
// TODO
}
}
}
接下来的问题是:性能如何对您来说很重要? I / O操作(这样的文件写入)很昂贵。 lock
也可能很贵。
答案 1 :(得分:0)
设置怎么样?转到项目的属性,然后选择设置选项。然后单击超链接以创建新的设置类(如果您当前没有设置)。白色Id字段的名称,设置类型和初始值。然后你可以在代码中使用它:
static readonly object Sync = new object();
public static void IncrementId()
{
lock(Sync)
{
Console.WriteLine(Properties.Settings.Default.Id);
Properties.Settings.Default.Id++;
Properties.Settings.Default.Save();
Console.WriteLine(Properties.Settings.Default.Id);
}
}
答案 2 :(得分:0)
这是我能想到的最快的。
磁盘不像它看起来那么可靠。即使是正确的写也不能保持可靠。通过OS缓冲区和磁盘缓冲区传递写入可能需要很长时间。
在这段代码中,我尽可能快地写,但读取/递增速度更快。从最后一次写入到实际状态,总有可能丢失一些ID。唯一的100%解决方案是以锁定步骤进行写入和刷新,但性能明显更差。
此示例是VB-DotNet控制台应用程序。
Imports System.Threading
Module Module1
Dim globalLong As Long = -1
Dim globalLongLock As New Object
Dim fileWriterThread As New Thread(AddressOf writerLoop)
Dim fileWriterSemaphore As New SemaphoreSlim(0)
Sub Main()
fileWriterThread.Start()
For i = 0 To 100
Tasks.Parallel.For(0, 100, Sub(n) nextID())
Next
Console.WriteLine("done")
Console.ReadKey()
End Sub
Function nextID() As Long
'
' load if required
'
If globalLong < 0 Then '\
SyncLock globalLongLock ' note the double IFs
If globalLong < 0 Then '/
'TODO: load from file
globalLong = 1
End If
End SyncLock
End If
'
' increment it
'
Dim id = Interlocked.Increment(globalLong)
'
' ask writer to store it
'
fileWriterSemaphore.Release()
Return id
End Function
Sub writerLoop()
Dim valueLastWritten As Long = -1
While True
fileWriterSemaphore.Wait()
Dim valueToWrite = globalLong
If valueToWrite > valueLastWritten Then
'TODO: write 'valueToWrite' to file
Console.WriteLine("Persisting " & valueToWrite)
IO.File.WriteAllText("d:\n.txt", valueToWrite.ToString)
valueLastWritten = valueToWrite
End If
End While
End Sub
End Module