我有这个代码。它给了我一个错误:
目标数组不够长,无法复制中的所有项目 采集。检查数组索引和长度。
我认为这是因为使用了字典,所以我将其切换为ConcurrentDictionary
,但错误仍在此处。
private void SaverCallback()
{
AddThread("Main Thread");
const string path = "milestone";
while (!stop)
{
ConcurrentDictionary<string, object> milestone = new ConcurrentDictionary<string, object>();
milestone.TryAdd("Jobs", JobQueue.Queue.MainQueue);
milestone.TryAdd("Locked Jobs", JobQueue.Queue.LockedQueue);
again: try {
using (FileStream writingStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
{
BinaryFormatter formater = new BinaryFormatter();
formater.Serialize(writingStream, milestone);
writingStream.Flush();
Logger.Debug("Status saved");
}
}
catch(Exception e)
{
Logger.Error($"Milestone exception: {e.Message}");
goto again;
}
this.WaitTime(60000);
}
RemoveThread();
}
UPD:
目标数组不够长,无法复制中的所有项目 采集。检查数组索引和长度。并在 System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) 在System.Collections.Generic.Dictionary
2.CopyTo(KeyValuePair
2 [] 数组,Int32索引)at System.Collections.Generic.Dictionary`2.GetObjectData(的SerializationInfo info,StreamingContext context)at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(对象 obj,ISurrogateSelector surrogateSelector,StreamingContext context, SerObjectInfoInit serObjectInfoInit,IFormatterConverter转换器, ObjectWriter objectWriter,SerializationBinder binder)at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo,NameInfo memberNameInfo,NameInfo typeNameInfo)at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteArrayMember(WriteObjectInfo objectInfo,NameInfo arrayElemTypeNameInfo,Object data)at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteArray(WriteObjectInfo objectInfo,NameInfo memberNameInfo,WriteObjectInfo memberObjectInfo) 在 System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo,NameInfo memberNameInfo,NameInfo typeNameInfo)at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(对象 graph,Header [] inHeaders,__BinaryWerer serWriter,Boolean fCheck)
在 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(流 serializationStream,Object graph,Header [] headers,Boolean fCheck)
在AggregateRunner.Enteties.Saver.SaverCallback()
答案 0 :(得分:0)
为避免此错误,我在尝试序列化文件之前使用lock。 现在它正常工作。
答案 1 :(得分:0)
据我所知,您每小时都会为您的队列拍摄一张快照,但代码的主要问题是您正在尝试序列化您的队列({{{{ 1}},我猜)本身没有任何克隆或同步逻辑。您的代码的另一个问题是ConcurrentQueue<T>
用法,这里根本不需要。
您面临的例外情况是goto
,是ArgumentException
的{{1}} CopyTo
方法。在序列化期间发生了这种情况,因为某些线程将一些消息添加到队列中,现在它不适合决定使用的阵列序列化器。
因此,在这种情况下你可以做的是在访问原始队列期间引入一些锁定(你决定这样做),或者为你的队列创建一个克隆并以安全的方式序列化阻止其他线程。
您可以自己使用ConcurrentQueue<T>
ConcurrentQueue<T>
方法执行此操作,创建长度大于队列中消息数的数组,但锁定通常是克隆数据的更方便的方法。所以你的代码应该是这样的:
private void SaverCallback()
{
AddThread("Main Thread");
const string path = "milestone";
while (!stop)
{
try
{
lock (JobQueue.Queue.MainQueue)
lock (JobQueue.Queue.LockedQueue)
{
using (var writingStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
{
var milestone = new ConcurrentDictionary<string, object>();
milestone.TryAdd("Jobs", JobQueue.Queue.MainQueue);
milestone.TryAdd("Locked Jobs", JobQueue.Queue.LockedQueue);
var formater = new BinaryFormatter();
formater.Serialize(writingStream, milestone);
writingStream.Flush();
Logger.Debug("Status saved");
}
}
// this line cloud be in finally case too,
// if you don't need to save a queue in case of some errors
this.WaitTime(60000);
}
catch(Exception e)
{
// note that logger accepts whole exception information
// instead of only it's message
Logger.Error($"Milestone exception: {e}");
continue;
}
}
RemoveThread();
}