我正在尝试为我的成就系统创建一个异步保存数据的任务。该任务每 1 分钟从主代码运行一次,但也可以在任何其他时间运行。
我想实现这些目标:
到目前为止,我尝试了不同的选择,这是最后一个:
数据仓库和保存任务调度器:
public class AchievementSaveTask : ISafeMemory {
private bool cancelled;
private Task currentSource;
private ConcurrentDictionary<int, AchievementData> aDatas;
public AchievementSaveTask() => aDatas = MouseAchievementFile.Read();
public async Task StartWriting() {
await CancelWrite();
currentSource = Task.Run(() => MouseAchievementFile.Write(aDatas, cancelled));
await currentSource;
currentSource.Dispose();
currentSource = null;
}
public async Task CancelWrite() {
if (currentSource != null) {
cancelled = true;
await currentSource;
cancelled = false;
currentSource.Dispose();
currentSource = null;
}
}
}
将数据写入文件的类:
public class MouseAchievementFile {
private const string FOLDER = "MouseWorld/Achievement", FILE = "achievements.mdat";
public static void Write(ConcurrentDictionary<int, AchievementData> data, in bool cancelled = false) {
var pathDir = Combine(Main.SavePath, FOLDER);
if (!Directory.Exists(pathDir)) Directory.CreateDirectory(pathDir);
//Execution stops somewhere here, why?
using (var bw = new BinaryWriter(File.Open(Combine(pathDir, FILE), FileMode.Create))) {
foreach ((_, var value) in data) {
var datas = value.GetRawData();
foreach (var currData in datas) {
if (!CheckWrite(bw, currData, cancelled)) {
datas.Clear();
return;
}
}
datas.Clear();
}
}
}
private static bool CheckWrite(BinaryWriter bw, string source, in bool cancelled) {
if (!cancelled) {
bw.Write(source);
return true;
}
else {
bw.Flush();
bw.Close();
bw.Dispose();
return false;
}
}
}
扩展方法:
public static void HandleException(this Task source, Action<Exception> exceptionHandler) {
source.ContinueWith(t => exceptionHandler(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
}
电话:
if (wait) achievementSaveTask.StartWriting().Wait();
else achievementSaveTask.StartWriting().HandleException(t => MWMod.Instance.Logger.WarnFormat("MAChievementManager.SaveAchievements() - WARNING! Could not save dict. Exception: {0}\r{1}", t.Message, t.StackTrace));
经过一些实验,我尝试更改我的代码以使用异步等待。虽然它在控制台应用程序中工作(向控制台输出一个字符串),但在实际情况下,我需要编写一个文件,程序会冻结。根据经验,我发现这大约发生在创建 BinaryWriter 时。我猜这是一个僵局。
评论里说了,BinaryWriter不适合异步写,但是写二进制形式的数据对我来说很重要,我不明白我怎么拒绝。
对此,出现以下问题: