c# - 异步任务减慢代码(散列)
问题描述
我正在编写一个在单词列表上执行散列的 Windows 窗体应用程序。为了确保在散列进行时应用程序不会冻结,我正在使用异步任务来执行散列。但是,这样做会导致处理哈希的速度从每秒数千个下降到每秒大约 60 个。
我的哈希函数是这样的
private static string MD5Hash(string word)
{
var stringBuilder = new StringBuilder();
var MD5 = new MD5CryptoServiceProvider();
var bytes = MD5.ComputeHash(new UTF8Encoding().GetBytes(word));
foreach (var value in bytes)
{
stringBuilder.Append(value.ToString("X2"));
}
return stringBuilder.ToString();
}
我实现了散列函数来从这样的文件中散列单词(这没有使用异步,它每秒可以实现几千个散列)
private static void DoHashes()
{
foreach (var word in File.ReadLines("the file path"))
{
File.AppendAllText("the output path", MD5Hash(word) + Environment.NewLine);
}
}
然后我使用了一个异步任务来避免像这样冻结我的 Windows 窗体应用程序(这导致哈希的速度下降到每秒 60 左右)
private static async void DoHashes()
{
await Task.Run(() =>
{
foreach (var word in File.ReadLines("the file path"))
{
File.AppendAllText("the output path", MD5Hash(word) + Environment.NewLine);
}
});
}
如何避免这种速度下降,而不会导致我的 Windows 窗体在执行哈希时冻结?
解决方案
我已经使用 WPF 应用程序完成了这个测试。在我的测试环境中,我使用了一个包含 5000 行的文件。以下是回复
|-------------------------------------------------------------------------------------
|# Description Time Taken (in secs)
|-------------------------------------------------------------------------------------
|1 Without Async/Await (As mentioned in the question) 144.933
|2 With Async/Await (As mentioned in the question) 145.563
|3 Using StringBuilder and writing to file only once 0.143
|4 With Async/Await and set ConfigureAwait to false 90.657
|-------------------------------------------------------------------------------------
如果您看到结果,则 Test#1 和 Test#2 之间没有重大区别,因此包装到 async-await 不会对您的方案产生影响。
下面是测试#3 和#4 的代码
测试 3(使用 StringBuilder 并仅写入文件一次)
private static async void DoHashes()
{
Stopwatch sw = new Stopwatch();
sw.Start();
await Task.Run(() =>
{
StringBuilder sb = new StringBuilder();
foreach (var word in File.ReadLines(Input file path))
{
sb.AppendLine(MD5Hash(word));
}
File.AppendAllText(Output file path, sb.ToString());
});
sw.Stop();
MessageBox.Show("Time Taken by Do Hashes : " + (sw.ElapsedMilliseconds / 1000.0) + " secs");
}
该测试的结果是0.143(比测试#1 和 #2 好 1000 倍),因为进程没有多次获取文件句柄。
测试 4(使用 Async/Await 并将 ConfigureAwait 设置为 false)
private static async void DoHashes()
{
Stopwatch sw = new Stopwatch();
sw.Start();
await Task.Run(() =>
{
foreach (var word in File.ReadLines(Input file path)
{
File.AppendAllText(Output file path, MD5Hash(word) + Environment.NewLine);
}
}).ConfigureAwait(false);
sw.Stop();
MessageBox.Show("Time Taken by Do Hashes : " + (sw.ElapsedMilliseconds / 1000.0) + " secs");
}
将ConfigureAwait
尝试设置为不将继续编组回捕获的原始上下文,这样您就可以看到性能有所提高 --- 与 Test#1 和 Test#2 相比,它需要的时间减少了40%(仅需要 90.657 秒)。
推荐阅读
- sql - 更新时间序列数据中的大量行
- photoshop-script - 裁剪而不删除裁剪的像素?- Photoshop 扩展脚本
- facebook - Facebook Pixel / E-Commerce:Facebook Pixel 和 Conversions API 事件的重复数据删除
- android - 为什么按原样定义 SpannableString 相等性?
- bash - 用awk比较字符串两个文件
- reactjs - React-sortable-tree 节点高度增量问题
- javascript - 使用过滤器不显示使用简单 HTML 和 Js 的所有图像
- python - SSLError - 证书验证失败 [第一个问题已回答,代码仍然无法正常工作]
- python - seaborn热图中的重叠y轴标签
- java - 具有多个语句的切换规则