我正在开发ASP.NET Web应用程序。它需要大量的RAM。因此,我正在考虑内存映射文件。
但是,实现内存映射文件非常麻烦。它需要使用那些内存地址,SizeOf运算符等。(我的时间不多了)。
当前系统正在使用大量的字典来存储大量数据。所有类都是[可序列化]。 有没有办法封装对内存映射文件的访问权限,
(C# Psedo-code)
var WrittingObject = new blablabla;
SetMMFVariable(name: "var1", value : WrittingObject);
var ReadingObject = GetMMFVariable(name: "var1");
.NET中是否有用于内存映射文件的包装代码?我不必担心那些内存地址和其他内容。
答案 0 :(得分:1)
这将是数据库的绝佳候选人!您遇到的问题是一次对大量信息进行序列化/反序列化。如果您需要阅读或更新一小部分信息,则需要扫描整个文件以更新SINGLE记录。这太疯狂了!
解决方法是拥有一些结构化的数据模型。您可以分发模型读/写以使用OS上的许多小文件(遭受损坏,DISK问题,权限问题,多次访问和文件锁定)来解决上述序列化问题,也可以转到实际的数据库将允许您查询和更新/插入所需的信息。
对于结构化模型(C#擅长于此),请查看Sql Server Express https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/sql-server-express-localdb?view=sql-server-2017
对于非结构化信息(json),请看一些非关系性的东西,例如bedbase https://docs.couchbase.com/dotnet-sdk/2.7/start-using-sdk.html
答案 1 :(得分:0)
我解决了。 这是一点点凌乱的代码。它与项目的其他部分有关。但是您可以轻松地使其便携。
(Visual Basic .NET代码)
Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Web.UI
Public Module UserStates
Public Property CurrSessionVariableIndex As Integer
Get
Dim I As Integer
If LDB.CustomData.TryGetValue("CurrSessionIndex", I) Then
Return I
Else
LDB.CustomData("CurrSessionIndex") = 1
Return I
End If
End Get
Set(value As Integer)
LDB.CustomData("CurrSessionIndex") = value
End Set
End Property
Public Function NewSessionVariableIndex() As Integer
CurrSessionVariableIndex += 1
Return CurrSessionVariableIndex
End Function
Public PreferMemoryMapFiles As Boolean = True
Public ViewStatusBags As New Dictionary(Of Integer, Dictionary(Of String, Object))(300)
Public ViewStatusTimes As New Dictionary(Of Integer, DateTime)(300)
Public Sub SetViewVarRAM(ViewStateID As Integer, key As String, Obj As Object)
Dim Bag As Dictionary(Of String, Object) = Nothing
If ViewStatusBags.TryGetValue(ViewStateID, Bag) Then
Try
Bag(key) = Obj
Catch ex As Exception
Log($"Added new ViewBag.Var {ViewStateID}.{key}")
Bag.Add(key, Obj)
End Try
ViewStatusTimes(ViewStateID) = Now
Else
Log($"Added new ViewBag {ViewStateID}")
Bag = New Dictionary(Of String, Object)
ViewStatusBags.Add(ViewStateID, Bag)
ViewStatusTimes.Add(ViewStateID, Now)
Bag.Add(key, Obj)
End If
End Sub
Public Function GetViewVarRAM(ViewStateID As Integer, key As String) As Object
Dim Bag As Dictionary(Of String, Object) = Nothing
If ViewStatusBags.TryGetValue(ViewStateID, Bag) Then
ViewStatusTimes(ViewStateID) = Now
Try
Return Bag(key)
Catch ex As Exception
Log($"Added new ViewBag.Var {ViewStateID}.{key}")
Bag.Add(key, Nothing)
Return Bag(key)
End Try
Else
Log($"Added new ViewBag {ViewStateID}")
Bag = New Dictionary(Of String, Object)
ViewStatusBags.Add(ViewStateID, Bag)
ViewStatusTimes.Add(ViewStateID, Now)
Bag.Add(key, Nothing)
Return Bag(key)
End If
End Function
Public Function GetViewMMF(ViewStateID As Integer) As Dictionary(Of String, Object)
Dim FS As FileStream = Nothing
Dim BF As New BinaryFormatter
GetFileStream(ViewStateID, FS)
Dim Bag As Dictionary(Of String, Object)
Try
Bag = BF.Deserialize(FS)
Catch ex As Exception
If Not ex.Message.StartsWith("Attempting to deserialize an empty stream") Then
LogError(ex, $"@MMF.Get : cannot Deserialize FS {ViewStateID}")
End If
FS.Flush()
Bag = New Dictionary(Of String, Object)
SetViewMMF(ViewStateID, Bag)
End Try
Try
FS.Flush()
Catch ex As Exception
End Try
Return Bag
End Function
Public Sub SetViewMMF(ViewStateID As Integer, Bag As Dictionary(Of String, Object))
Dim FS As FileStream = Nothing
Dim BF As New BinaryFormatter
GetFileStream(ViewStateID, FS)
Try
BF.Serialize(FS, Bag)
Catch ex As Exception
LogError(ex, $"@MMF.Set : cannot Serialize FS {ViewStateID}")
FS.Flush()
End Try
Try
FS.Flush()
Catch ex As Exception
End Try
End Sub
Public MMFStreams As New Dictionary(Of Integer, FileStream)(100)
Public MMFStreamsTimes As New Dictionary(Of Integer, Date)(100)
Public FilePathMMFs As String
Private Sub GetFileStream(ByRef ViewStateID As Integer, ByRef FS As FileStream)
If MMFStreams.TryGetValue(ViewStateID, FS) Then
Try
FS.Seek(0, SeekOrigin.Begin)
Catch ex As Exception
LogError(ex, $"@MMF.Set : cannot restart FS {ViewStateID}")
FS = New FileStream(FilePathMMFs & ViewStateID.ToString & "-" & Rand.Next(100, 1000).ToString, FileMode.OpenOrCreate)
FS.Seek(0, SeekOrigin.Begin)
MMFStreams(ViewStateID) = FS
End Try
MMFStreamsTimes(ViewStateID) = Now
Else
Try
FS = New FileStream(FilePathMMFs & ViewStateID.ToString, FileMode.OpenOrCreate)
FS.Seek(0, SeekOrigin.Begin)
MMFStreams.Add(ViewStateID, FS)
Catch ex As Exception
LogError(ex, $"@MMF.Set : cannot OpenOrCreate new FS {ViewStateID}")
FS = New FileStream(FilePathMMFs & ViewStateID.ToString & "-" & Rand.Next(100, 1000).ToString, FileMode.OpenOrCreate)
FS.Seek(0, SeekOrigin.Begin)
MMFStreams.Add(ViewStateID, FS)
End Try
MMFStreamsTimes(ViewStateID) = Now
End If
End Sub
Public Sub SetViewVarMMF(ViewStateID As Integer, key As String, Obj As Object)
Dim FS As FileStream = Nothing
Dim BF As New BinaryFormatter
GetFileStream(ViewStateID, FS)
Dim Bag As Dictionary(Of String, Object)
Try
Bag = BF.Deserialize(FS)
Catch ex As Exception
'LogError(ex, $"@MMF.SetViewVarMMF : cannot Deserialize FS {ViewStateID}. saved new bag")
Bag = New Dictionary(Of String, Object)
End Try
FS.Seek(0, SeekOrigin.Begin)
If Bag.ContainsKey(key) Then
Bag(key) = Obj
Else
Bag.Add(key, Obj)
End If
Try
BF.Serialize(FS, Bag)
Catch ex As Exception
LogError(ex, $"@MMF.SetViewVarMMF : cannot Serialize FS {ViewStateID}")
FS.Flush()
End Try
Try
FS.Flush()
Catch ex As Exception
End Try
End Sub
Public Function GetViewVarMMF(ViewStateID As Integer, key As String) As Object
Dim Bag = GetViewMMF(ViewStateID)
Dim Obj As Object = Nothing
If Bag.TryGetValue(key, Obj) Then
Return Obj
Else
Return Nothing
End If
Bag = Nothing
End Function
Public AllUserContainer As New Dictionary(Of Integer, UserContainer)(50)
Public Sub SetUserContainer(Usr As Integer, Con As UserContainer)
Con.UserID = Usr
If AllUserContainer.ContainsKey(Usr) Then
AllUserContainer(Usr) = Con
Con.Time = Now
Else
Log($"Added new user {Usr}")
AllUserContainer.Add(Usr, Con)
Con.Time = Now
End If
End Sub
Public Function GetUserContainer(Usr As Integer) As UserContainer
Dim Con As UserContainer = Nothing
If AllUserContainer.TryGetValue(Usr, Con) Then
Con.Time = Now
Return Con
Else
Log($"Added new user {Usr}")
Con = New UserContainer(Usr)
AllUserContainer.Add(Usr, Con)
Con.Time = Now
Return Con
End If
End Function
'___________________________________________________'
Public Sub SetViewVar(ViewStateID As Integer, key As String, Obj As Object)
If PreferMemoryMapFiles Then
SetViewVarMMF(ViewStateID, key, Obj)
Else
SetViewVarRAM(ViewStateID, key, Obj)
End If
End Sub
Public Function GetViewVar(ViewStateID As Integer, key As String) As Object
If PreferMemoryMapFiles Then
Return GetViewVarMMF(ViewStateID, key)
Else
Return GetViewVarRAM(ViewStateID, key)
End If
End Function
Public Sub RemoveMMF(ViewStateID As Integer)
Dim FS As FileStream = Nothing
If MMFStreams.TryGetValue(ViewStateID, FS) Then
Try
FS.Close()
Catch ex As Exception
End Try
End If
End Sub
Public Sub RemoveUserContainer(Usr As Integer)
If AllUserContainer.ContainsKey(Usr) Then
AllUserContainer(Usr).Dispose()
AllUserContainer.Remove(Usr)
Log($"Removed user {Usr}")
End If
End Sub
Public Sub DeleteUnusedMMFs()
Dim Files = Directory.GetFiles(FilePathMMFs)
Dim nowTime As Date = Now
Dim nOfFiles = 0I
For Each FilePath In Files
Dim FileID = Path.GetFileName(FilePath)
Dim Time As Date = Date.MinValue
If UserStates.MMFStreamsTimes.TryGetValue(FileID, Time) Then
If Time.AddMinutes(5) < nowTime Then
Try
UserStates.MMFStreams(FileID).Close()
Catch ex As Exception
End Try
Try
File.Delete(FilePath)
nOfFiles += 1
Catch ex As Exception
End Try
End If
Else
Try
File.Delete(FilePath)
nOfFiles += 1
Catch ex As Exception
End Try
End If
Next
Log($"@ViewStates.DeleteUnusedMMFs : {nOfFiles} deleted")
End Sub
'___________________________________________________'
Public Sub ClearUnusedViewStates()
Dim BeforeRAM = (My.Application.Info.WorkingSet / 1024) / 1024
Dim CurrTime = Now
Dim ToRemove As New List(Of Integer)
Dim ViewEntries As Integer
Dim UsrEntries As Integer
If ViewStatusBags.Count = 0 Then
GoTo RemoveusrsLbl
End If
For i = ViewStatusBags.Count - 1 To 0 Step -1
Dim Time = ViewStatusTimes.ElementAt(i).Value
If Time.AddMinutes(5) < CurrTime Then
ToRemove.Add(ViewStatusBags.ElementAt(i).Key)
End If
Next
ViewEntries = ToRemove.Count
For Each i In ToRemove
ViewStatusBags.Remove(i)
Next
RemoveusrsLbl:
If AllUserContainer.Count = 0 Then
GoTo Final
End If
For i = AllUserContainer.Count - 1 To 0 Step -1
If AllUserContainer(i).Time.AddMinutes(15) < CurrTime Then
AllUserContainer.Remove(AllUserContainer(i).UserID)
UsrEntries += 1
End If
Next
Final:
GC.Collect()
Dim AfterRAM = (My.Application.Info.WorkingSet / 1024) / 1024
Log($"@ViewStates : {ViewEntries} Unused ViewStates Cleared. {UsrEntries} inactive users cleared. {AfterRAM - BeforeRAM} MB Cleared. ")
End Sub
End Module
(C#代码)(翻译)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualBasic;
using System.Runtime.Serialization.Formatters.Binary;
using System.Web.UI;
public static class UserStates
{
public static int CurrSessionVariableIndex
{
get
{
int I;
if (LDB.CustomData.TryGetValue("CurrSessionIndex", I))
return I;
else
{
LDB.CustomData("CurrSessionIndex") = 1;
return I;
}
}
set
{
LDB.CustomData("CurrSessionIndex") = value;
}
}
public static int NewSessionVariableIndex()
{
CurrSessionVariableIndex += 1;
return CurrSessionVariableIndex;
}
public static bool PreferMemoryMapFiles = true;
public static Dictionary<int, Dictionary<string, object>> ViewStatusBags = new Dictionary<int, Dictionary<string, object>>(300);
public static Dictionary<int, DateTime> ViewStatusTimes = new Dictionary<int, DateTime>(300);
public static void SetViewVarRAM(int ViewStateID, string key, object Obj)
{
Dictionary<string, object> Bag = null;
if (ViewStatusBags.TryGetValue(ViewStateID, out Bag))
{
try
{
Bag[key] = Obj;
}
catch (Exception ex)
{
Log($"Added new ViewBag.Var {ViewStateID}.{key}");
Bag.Add(key, Obj);
}
ViewStatusTimes[ViewStateID] = DateTime.Now;
}
else
{
Log($"Added new ViewBag {ViewStateID}");
Bag = new Dictionary<string, object>();
ViewStatusBags.Add(ViewStateID, Bag);
ViewStatusTimes.Add(ViewStateID, DateTime.Now);
Bag.Add(key, Obj);
}
}
public static object GetViewVarRAM(int ViewStateID, string key)
{
Dictionary<string, object> Bag = null;
if (ViewStatusBags.TryGetValue(ViewStateID, out Bag))
{
ViewStatusTimes[ViewStateID] = DateTime.Now;
try
{
return Bag[key];
}
catch (Exception ex)
{
Log($"Added new ViewBag.Var {ViewStateID}.{key}");
Bag.Add(key, null);
return Bag[key];
}
}
else
{
Log($"Added new ViewBag {ViewStateID}");
Bag = new Dictionary<string, object>();
ViewStatusBags.Add(ViewStateID, Bag);
ViewStatusTimes.Add(ViewStateID, DateTime.Now);
Bag.Add(key, null);
return Bag[key];
}
}
public static Dictionary<string, object> GetViewMMF(int ViewStateID)
{
FileStream FS = null;
BinaryFormatter BF = new BinaryFormatter();
GetFileStream(ref ViewStateID, ref FS);
Dictionary<string, object> Bag;
try
{
Bag = BF.Deserialize(FS);
}
catch (Exception ex)
{
if (!ex.Message.StartsWith("Attempting to deserialize an empty stream"))
LogError(ex, $"@MMF.Get : cannot Deserialize FS {ViewStateID}");
FS.Flush();
Bag = new Dictionary<string, object>();
SetViewMMF(ViewStateID, Bag);
}
try
{
FS.Flush();
}
catch (Exception ex)
{
}
return Bag;
}
public static void SetViewMMF(int ViewStateID, Dictionary<string, object> Bag)
{
FileStream FS = null;
BinaryFormatter BF = new BinaryFormatter();
GetFileStream(ref ViewStateID, ref FS);
try
{
BF.Serialize(FS, Bag);
}
catch (Exception ex)
{
LogError(ex, $"@MMF.Set : cannot Serialize FS {ViewStateID}");
FS.Flush();
}
try
{
FS.Flush();
}
catch (Exception ex)
{
}
}
public static Dictionary<int, FileStream> MMFStreams = new Dictionary<int, FileStream>(100);
public static Dictionary<int, DateTime> MMFStreamsTimes = new Dictionary<int, DateTime>(100);
public static string FilePathMMFs;
private static void GetFileStream(ref int ViewStateID, ref FileStream FS)
{
if (MMFStreams.TryGetValue(ViewStateID, out FS))
{
try
{
FS.Seek(0, SeekOrigin.Begin);
}
catch (Exception ex)
{
LogError(ex, $"@MMF.Set : cannot restart FS {ViewStateID}");
FS = new FileStream(FilePathMMFs + ViewStateID.ToString() + "-" + Rand.Next(100, 1000).ToString, FileMode.OpenOrCreate);
FS.Seek(0, SeekOrigin.Begin);
MMFStreams[ViewStateID] = FS;
}
MMFStreamsTimes[ViewStateID] = DateTime.Now;
}
else
{
try
{
FS = new FileStream(FilePathMMFs + ViewStateID.ToString(), FileMode.OpenOrCreate);
FS.Seek(0, SeekOrigin.Begin);
MMFStreams.Add(ViewStateID, FS);
}
catch (Exception ex)
{
LogError(ex, $"@MMF.Set : cannot OpenOrCreate new FS {ViewStateID}");
FS = new FileStream(FilePathMMFs + ViewStateID.ToString() + "-" + Rand.Next(100, 1000).ToString, FileMode.OpenOrCreate);
FS.Seek(0, SeekOrigin.Begin);
MMFStreams.Add(ViewStateID, FS);
}
MMFStreamsTimes[ViewStateID] = DateTime.Now;
}
}
public static void SetViewVarMMF(int ViewStateID, string key, object Obj)
{
FileStream FS = null;
BinaryFormatter BF = new BinaryFormatter();
GetFileStream(ref ViewStateID, ref FS);
Dictionary<string, object> Bag;
try
{
Bag = BF.Deserialize(FS);
}
catch (Exception ex)
{
// LogError(ex, $"@MMF.SetViewVarMMF : cannot Deserialize FS {ViewStateID}. saved new bag")
Bag = new Dictionary<string, object>();
}
FS.Seek(0, SeekOrigin.Begin);
if (Bag.ContainsKey(key))
Bag[key] = Obj;
else
Bag.Add(key, Obj);
try
{
BF.Serialize(FS, Bag);
}
catch (Exception ex)
{
LogError(ex, $"@MMF.SetViewVarMMF : cannot Serialize FS {ViewStateID}");
FS.Flush();
}
try
{
FS.Flush();
}
catch (Exception ex)
{
}
}
public static object GetViewVarMMF(int ViewStateID, string key)
{
var Bag = GetViewMMF(ViewStateID);
object Obj = null;
if (Bag.TryGetValue(key, out Obj))
return Obj;
else
return null;
Bag = null;
}
public static Dictionary<int, UserContainer> AllUserContainer = new Dictionary<int, UserContainer>(50);
public static void SetUserContainer(int Usr, UserContainer Con)
{
Con.UserID = Usr;
if (AllUserContainer.ContainsKey(Usr))
{
AllUserContainer[Usr] = Con;
Con.Time = DateTime.Now;
}
else
{
Log($"Added new user {Usr}");
AllUserContainer.Add(Usr, Con);
Con.Time = DateTime.Now;
}
}
public static UserContainer GetUserContainer(int Usr)
{
UserContainer Con = null/* TODO Change to default(_) if this is not a reference type */;
if (AllUserContainer.TryGetValue(Usr, out Con))
{
Con.Time = DateTime.Now;
return Con;
}
else
{
Log($"Added new user {Usr}");
Con = new UserContainer(Usr);
AllUserContainer.Add(Usr, Con);
Con.Time = DateTime.Now;
return Con;
}
}
// ___________________________________________________'
public static void SetViewVar(int ViewStateID, string key, object Obj)
{
if (PreferMemoryMapFiles)
SetViewVarMMF(ViewStateID, key, Obj);
else
SetViewVarRAM(ViewStateID, key, Obj);
}
public static object GetViewVar(int ViewStateID, string key)
{
if (PreferMemoryMapFiles)
return GetViewVarMMF(ViewStateID, key);
else
return GetViewVarRAM(ViewStateID, key);
}
public static void RemoveMMF(int ViewStateID)
{
FileStream FS = null;
if (MMFStreams.TryGetValue(ViewStateID, out FS))
{
try
{
FS.Close();
}
catch (Exception ex)
{
}
}
}
public static void RemoveUserContainer(int Usr)
{
if (AllUserContainer.ContainsKey(Usr))
{
AllUserContainer[Usr].Dispose();
AllUserContainer.Remove(Usr);
Log($"Removed user {Usr}");
}
}
public static void DeleteUnusedMMFs()
{
var Files = Directory.GetFiles(FilePathMMFs);
DateTime nowTime = DateTime.Now;
var nOfFiles = 0;
foreach (var FilePath in Files)
{
var FileID = Path.GetFileName(FilePath);
DateTime Time = DateTime.MinValue;
if (UserStates.MMFStreamsTimes.TryGetValue(FileID, out Time))
{
if (Time.AddMinutes(5) < nowTime)
{
try
{
UserStates.MMFStreams[FileID].Close();
}
catch (Exception ex)
{
}
try
{
File.Delete(FilePath);
nOfFiles += 1;
}
catch (Exception ex)
{
}
}
}
else
try
{
File.Delete(FilePath);
nOfFiles += 1;
}
catch (Exception ex)
{
}
}
Log($"@ViewStates.DeleteUnusedMMFs : {nOfFiles} deleted");
}
// ___________________________________________________'
public static void ClearUnusedViewStates()
{
var BeforeRAM = (My.Application.Info.WorkingSet / (double)1024) / (double)1024;
var CurrTime = DateTime.Now;
List<int> ToRemove = new List<int>();
int ViewEntries;
int UsrEntries;
if (ViewStatusBags.Count == 0)
goto RemoveusrsLbl;
for (var i = ViewStatusBags.Count - 1; i >= 0; i += -1)
{
var Time = ViewStatusTimes.ElementAt(i).Value;
if (Time.AddMinutes(5) < CurrTime)
ToRemove.Add(ViewStatusBags.ElementAt(i).Key);
}
ViewEntries = ToRemove.Count;
foreach (var i in ToRemove)
ViewStatusBags.Remove(i);
RemoveusrsLbl:
;
if (AllUserContainer.Count == 0)
goto Final;
for (var i = AllUserContainer.Count - 1; i >= 0; i += -1)
{
if (AllUserContainer[i].Time.AddMinutes(15) < CurrTime)
{
AllUserContainer.Remove(AllUserContainer[i].UserID);
UsrEntries += 1;
}
}
Final:
;
GC.Collect();
var AfterRAM = (My.Application.Info.WorkingSet / (double)1024) / (double)1024;
Log($"@ViewStates : {ViewEntries} Unused ViewStates Cleared. {UsrEntries} inactive users cleared. {AfterRAM - BeforeRAM} MB Cleared. ");
}
}