早上好,
在我正在编写的应用程序启动时,我需要阅读从文件到Dictionary<Tuple<String, String>, Int32>
的大约1,600,000个条目。使用BinaryReader构建整个结构大约需要4-5秒(使用FileReader需要大约相同的时间)。我分析了代码并发现在此过程中执行最多工作的函数是BinaryReader.ReadString()
。虽然这个过程只需要运行一次并在启动时运行,但我希望尽可能快地完成。有什么方法可以避免BinaryReader.ReadString()
并使这个过程更快?
非常感谢。
答案 0 :(得分:5)
在继续之前,您确定绝对必须这样做吗?
我会检查将任务转移到一个单独的线程的可能性,该线程在完成时设置一个标志。然后你的启动代码就会启动那个线程并继续它的快乐方式,只在以下两个时候暂停:
通常情况下,幻觉的速度已经足够好了,因为任何编写了闪屏的人都会告诉你。
如果你控制数据,另一种可能性是将它存储在一个更加二进制的形式中,这样你就可以用一次命中将它全部放入(即,没有对数据的解释,只读完整个事物)。当然,这使得从应用程序外部编辑数据变得更加困难,但您没有将其作为一项要求。
如果 是一项要求,或者您无法控制数据,我仍会查看上面的第一条建议。
答案 1 :(得分:0)
如果在元组内重复字符串,您可以重新组织文件,使其在开始时具有所有不同的涉及字符串,并在文件正文中引用这些字符串(整数)。您的主词典不必更改,但在启动期间需要一个临时词典,包含所有不同的字符串(值)及其引用(键)。
答案 2 :(得分:0)
如果您认为逐行读取文件是瓶颈,取决于其大小,您可以尝试一次性阅读:
// read the entire file at once
string entireFile = System.IO.File.ReadAllText(path);
这没有帮助,您可以尝试添加一个带有信号量的单独线程,该信号量将在程序启动时立即开始在后台读取,但在您尝试访问时阻止请求线程数据。
这称为Future,你在Jon Skeet的miscutil库中有一个实现。
你在app启动时这样称呼它:
// following line invokes "DoTheActualWork" method on a background thread.
// DoTheActualWork returns an instance of MyData when it's done
Future<MyData> calculation = new Future<MyData>(() => DoTheActualWork(path));
然后,一段时间后,您可以访问主线程中的值:
// following line blocks the calling thread until
// the background thread completes
MyData result = calculation.Value;
如果查看Future的Value属性,如果线程仍在运行,您可以看到它在AsyncWaitHandle处阻塞:
public TResult Value
{
get
{
if (!IsCompleted)
{
_asyncResult.AsyncWaitHandle.WaitOne();
_lock.WaitOne();
}
return _value;
}
}