gpt4 book ai didi

c# - 异步读写器储物柜

转载 作者:行者123 更新时间:2023-11-30 16:59:37 26 4
gpt4 key购买 nike

现在,我正在尝试制作 a generic IsoStorageManager ,这将读/写和序列化/反序列化类异步,基于 this analytic .但是,我知道不同线程会请求相同文件进行读/写的情况。

我对这个领域的看法:

  1. 只需将所有 Reads()/Writes() 封装到一个锁中。 - 不太好,因为我不需要等待写入不同的文件。

  2. 为作者添加某种并发队列。如果同一个文件已经在处理中,writer 应该决定是要取消之前的任务(重写)还是从缓存中获取之前的任务并添加自己的更改(合并)。如果读者想要访问同一个文件,只需从队列中返回数据即可。 - 似乎过于复杂。

  3. 强制读者为所有作者使用一个线程。然后,我可以毫无问题地多次尝试访问同一文件。 - 作为临时解决方案似乎不错,这是这里的主要问题。其实和1一样。

  4. EDIT1:也许我需要一个线程安全的字典?一旦要写入文件,我会将其名称和数据存储在字典中,这样读者就可以从编写者本身获取数据。

有什么建议吗?

编辑2:

我正在使用任务

public static async Task<T> ReadJsonAsyncTask<T>(this JsonTextReader reader)
{
return await TaskEx.Run(() => jsonSerializer.Deserialize<T>(reader));
}

像这样

public static async Task<T> ReadJsonEx<T>(String fileName)
{
if (String.IsNullOrEmpty(fileName))
return default(T);

return await await Task.Factory.StartNew(async () =>
{
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
using (var stream = new IsolatedStorageFileStream(fileName, FileMode.Open, store))
using (var sr = new StreamReader(stream))
using (var jr = new JsonTextReader(sr))
return await jr.ReadJsonAsyncTask<T>();
});
}

writer 也一样,我想确保在此过程中不会访问任何文件。

EDIT3:啊哈,看起来我在这里找到了答案:Easy way to save game in WP7 Silverlight?

EDIT4:这仅适用于同步调用。不是我的情况。 :(

EDIT5:经过一整天的搜索,我找到了 AsyncReaderWriterLock .用法很简单:

private static readonly AsyncReaderWriterLock readerLocker = new AsyncReaderWriterLock(); 

public static async Task<T> ReadJsonEx<T>(String fileName)
{
if (String.IsNullOrEmpty(fileName))
return default(T);

return await await Task.Factory.StartNew(async () =>
{
using (var locker = await readLocker.ReaderLockAsync())
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
using (var stream = new IsolatedStorageFileStream(fileName, FileMode.Open, store))
using (var sr = new StreamReader(stream))
using (var jr = new JsonTextReader(sr))
return await jr.ReadJsonAsyncTask<T>();
});
}

有时有效,有时无效。

EDIT6:好的,这里有一些关于我的 AsyncReaderWriterLock 测试用例的更多细节。我有前面提到的阅读器和使用自己的 AsyncReaderWriterLock 的编写器。我有一个带有进度条和按钮的页面。按钮命令是:

SimpleLogger.WriteLine("Starting generation...");

var list = new List<Order>();
//for (var i = 0; i < 10; i++)
list.Add(GenerateOrder());


SimpleLogger.WriteLine("Writing 5 times the same file...");

var res1 = await IsoStorageManager.WriteJsonEx(fileName1, list);
var res2 = await IsoStorageManager.WriteJsonEx(fileName1, list);
var res3 = await IsoStorageManager.WriteJsonEx(fileName1, list);
var res4 = await IsoStorageManager.WriteJsonEx(fileName1, list);
var res5 = await IsoStorageManager.WriteJsonEx(fileName1, list);

SimpleLogger.WriteLine("Writing 5 different files");

var res11 = await IsoStorageManager.WriteJsonEx(fileName1, list);
var res12 = await IsoStorageManager.WriteJsonEx(fileName2, list);
var res13 = await IsoStorageManager.WriteJsonEx(fileName3, list);
var res14 = await IsoStorageManager.WriteJsonEx(fileName4, list);
var res15 = await IsoStorageManager.WriteJsonEx(fileName5, list);

SimpleLogger.WriteLine("Reading 5 times the same");

var res21 = await IsoStorageManager.ReadJsonEx<List<Order>>(fileName1);
var res22 = await IsoStorageManager.ReadJsonEx<List<Order>>(fileName1);
var res23 = await IsoStorageManager.ReadJsonEx<List<Order>>(fileName1);
var res24 = await IsoStorageManager.ReadJsonEx<List<Order>>(fileName1);
var res25 = await IsoStorageManager.ReadJsonEx<List<Order>>(fileName1);

SimpleLogger.WriteLine("Reading 5 times different");

var res31 = await IsoStorageManager.ReadJsonEx<List<Order>>(fileName1);
var res32 = await IsoStorageManager.ReadJsonEx<List<Order>>(fileName2);
var res33 = await IsoStorageManager.ReadJsonEx<List<Order>>(fileName3);
var res34 = await IsoStorageManager.ReadJsonEx<List<Order>>(fileName4);
var res35 = await IsoStorageManager.ReadJsonEx<List<Order>>(fileName5);

SimpleLogger.WriteLine("Done");

如果按下按钮一次,或多或少可以(不同的文件不会同时写入,因为它应该在完美的世界中,但现在就这样吧):

09:03:38.262 [00:00:00.000] Starting generation...
09:03:38.300 [00:00:00.025] Writing 5 times the same file...
09:03:43.126 [00:00:04.811] Writing 5 different files
09:03:47.303 [00:00:04.163] Reading 5 times the same
09:03:50.194 [00:00:02.871] Reading 5 times different
09:03:53.341 [00:00:03.130] Done

如果多次按下按钮来模拟高负载和混合写入/读取内容,我得到以下输出:

08:51:52.680 [00:00:00.000] Starting generation...
08:51:52.722 [00:00:00.028] Writing 5 times the same file...
08:51:52.795 [00:00:00.057] Starting generation...
08:51:52.854 [00:00:00.043] Writing 5 times the same file...
08:51:52.892 [00:00:00.023] Starting generation...
08:51:52.922 [00:00:00.016] Writing 5 times the same file...
08:51:52.943 [00:00:00.006] Starting generation...
08:51:52.973 [00:00:00.016] Writing 5 times the same file...
08:52:06.009 [00:00:13.022] Writing 5 different files
08:52:06.966 [00:00:00.942] Writing 5 different files
08:52:07.811 [00:00:00.778] Writing 5 different files
08:52:08.513 [00:00:00.689] Writing 5 different files
08:52:22.115 [00:00:13.567] Reading 5 times the same
08:52:22.887 [00:00:00.755] Reading 5 times the same
08:52:23.773 [00:00:00.754] Reading 5 times the same

using (var stream = new IsolatedStorageFileStream(fileName, FileMode.Open, store))

行中的异常
System.IO.IOException occurred
_HResult=-2147024864
_message=[IO.IO_SharingViolation_File]
Arguments: Folder//TestFile1.txt
Debugging resource strings are unavailable. Often the key and arguments provide sufficient information to diagnose the problem. See http://go.microsoft.com/fwlink/?linkid=106663&Version=4.0.50829.0&File=mscorlib.dll&Key=IO.IO_SharingViolation_File
HResult=-2147024864
Message=[IO.IO_SharingViolation_File]
Arguments: Folder//TestFile1.txt
Debugging resource strings are unavailable. Often the key and arguments provide sufficient information to diagnose the problem. See http://go.microsoft.com/fwlink/?linkid=106663&Version=4.0.50829.0&File=mscorlib.dll&Key=IO.IO_SharingViolation_File
Source=mscorlib
StackTrace:
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
InnerException:

EDIT7:试过awaitable critical section .为单个命令(点击按钮)提供类似于 AsyncReaderWriterLock 结果:

03:12:05.213 [00:00:00.000] Starting generation...
03:12:05.252 [00:00:00.023] Writing 5 times the same file...
03:12:09.894 [00:00:04.626] Writing 5 different files
03:12:13.700 [00:00:03.792] Reading 5 times the same
03:12:16.831 [00:00:03.115] Reading 5 times different
03:12:20.032 [00:00:03.171] Done

而且这似乎通过碰撞测试(4 次快速按钮点击)更稳定:它设法在没有崩溃的情况下完成任务。

EDIT8:把所有的东西都移到了 Google Spreadshit .应该有一个很好的公共(public)访问(不需要登录)。稍后会将所有统计信息移到那里。

最佳答案

据我了解,您正计划创建一个可以异步运行的任务。 IMO 最好的会在这里 Mutex - 它旨在保护共享资源免受多重访问:

When two or more threads need to access a shared resource at the same time, the system needs a synchronization mechanism to ensure that only one thread at a time uses the resource. Mutex is a synchronization primitive that grants exclusive access to the shared resource to only one thread. If a thread acquires a mutex, the second thread that wants to acquire that mutex is suspended until the first thread releases the mutex.

Mutex 的另一个优点是 in 可以是全局的 - 您可以使用它来保护进程之间对文件的访问。

据我内存WP8.0写文件,序列化是同步完成的,然后因为是单线程运行,Mutex的获取和释放不会有问题。

Here you can find a good pattern.

编辑

我仍然不明白您要实现的目标以及问题所在。 IMO 你正在将你的反序列化重定向到 ThreadPool 线程,然后你可以使那里的代码同步(它不在 UI 线程上运行)并使用 Mutex。可能还有许多其他解决方案,但也许这会有所帮助:

public static async Task<T> ReadJsonEx<T>(String fileName)
{
if (String.IsNullOrEmpty(fileName)) return default(T);

string mutexName = "dependantOnApp" + fileName;
return await Task.Run<T>(() =>
{
using (Mutex myMutex = new Mutex(false, mutexName))
{
try
{
myMutex.WaitOne();
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
using (var stream = new IsolatedStorageFileStream(fileName, FileMode.Open, store))
using (var sr = new StreamReader(stream))
using (var jr = new JsonTextReader(sr))
return jsonSerializer.Deserialize<T>(jr);
}
catch { throw new Exception("Exception"); }
finally { myMutex.ReleaseMutex(); }
}
});
}

关于c# - 异步读写器储物柜,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23582262/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com