以前一直是做WEB开发,ASP.NET,最近公司要求做一个能生成5万条互不相同的字符串的功能.
用VS2005创建windows程序,windows程序写好后测试能生成5万条.但是效率很低,花了3分钟时间,CPU使用率在98%-100%之间徘徊.
我的代码如下,想请各位帮忙给优化下,让代码跑起来快些.(初次写windows程序,有很多不懂,希望在CSDN请教各位达人!)
Form1.cs代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Text;namespace createtxt
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} private void button1_Click(object sender, EventArgs e)
{
string code = "";
for (int i = 1; i <= 50000; i++)
{
code += rc(i) + "\r\n";
}
label1.Text="已生成五万条随机字符串";
string path = "D:/";
Encoding codee = Encoding.GetEncoding("UTF-8");
StreamWriter sw = new StreamWriter(path + "string.txt", false, codee);
sw.Write(code);
sw.Flush();
sw.Close();
label1.Text = "生成文件成功,文件名为:string.txt";
} public static string rc(int a)
{
char[] arrchar = new char[]{
'0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
};
StringBuilder num = new StringBuilder();
Random rnd = new Random(a);
for (int i = 1; i <= 4; i++)
{
//num2.Append(arrchar[rnd.Next(0,10)].ToString());
//num.Append(arrchar[rnd.Next(0, 10)].ToString());
num.Append(arrchar[rnd.Next(11, arrchar.Length)].ToString());
}
for (int j = 1; j <= 8; j++)
{
num.Append(arrchar[rnd.Next(0, 10)].ToString());
}
return num.ToString();
}
}
}
用VS2005创建windows程序,windows程序写好后测试能生成5万条.但是效率很低,花了3分钟时间,CPU使用率在98%-100%之间徘徊.
我的代码如下,想请各位帮忙给优化下,让代码跑起来快些.(初次写windows程序,有很多不懂,希望在CSDN请教各位达人!)
Form1.cs代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Text;namespace createtxt
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} private void button1_Click(object sender, EventArgs e)
{
string code = "";
for (int i = 1; i <= 50000; i++)
{
code += rc(i) + "\r\n";
}
label1.Text="已生成五万条随机字符串";
string path = "D:/";
Encoding codee = Encoding.GetEncoding("UTF-8");
StreamWriter sw = new StreamWriter(path + "string.txt", false, codee);
sw.Write(code);
sw.Flush();
sw.Close();
label1.Text = "生成文件成功,文件名为:string.txt";
} public static string rc(int a)
{
char[] arrchar = new char[]{
'0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
};
StringBuilder num = new StringBuilder();
Random rnd = new Random(a);
for (int i = 1; i <= 4; i++)
{
//num2.Append(arrchar[rnd.Next(0,10)].ToString());
//num.Append(arrchar[rnd.Next(0, 10)].ToString());
num.Append(arrchar[rnd.Next(11, arrchar.Length)].ToString());
}
for (int j = 1; j <= 8; j++)
{
num.Append(arrchar[rnd.Next(0, 10)].ToString());
}
return num.ToString();
}
}
}
解决方案 »
- 55555555遭遇XSS跨站漏洞啊。不知道怎么解决
- 学.net的同时在学习php会不会造成时间不够?
- 100分问题,TcpClient连接断开重新连接后BinaryReader的问题
- 在vs2008中怎样引用DataList空间中的子控件
- 请教!如何获得本机所在网络中域控制器(域)的集合?
- IE 自带的WebBrowser 控件打印怎么隐藏页眉页脚
- 我是一个刚毕业的女生也喜欢做程序但现在有问题不会了!各位高手请进
- C#写的winform程序用什么来发布?
- 谁送份C#的数据库程序学习学习?分不够开新贴送分
- 病毒找上我了,朋友们救我的命吧
- C#与C++编程语言选择问题(刚才忘记给分了)
- C#读取excel多个sheet中的变量进行求和,如何做比较简单?
for (int i = 1; i <= 50000; i++)
{
code += rc(i) + "\r\n"; // 这条语句导致频繁分配内存,code的内存最后为50000*(12 + 2)字节
}可以用文件流来写入,不用放在一个string中再写
另外楼主怎么保证不重复?
private byte[] codeBuffer = new byte[14 * CODE_COUNT];private Random random = new Random();
public byte[] RandomCode()
{
byte[] vReturn = new byte[14];
vReturn[12] = 13;
vReturn[13] = 10;
for (int i = 0; i < 4; i++)
vReturn[i] = (byte)('A' + random.Next(26));
for (int i = 4; i < 12; i++)
vReturn[i] = (byte)('0' + random.Next(10));
return vReturn;
}private Hashtable vHashtable = new Hashtable();private void button1_Click(object sender, EventArgs e)
{
long vTickCount = Environment.TickCount;
byte[] code = RandomCode();
for (int i = 0; i < CODE_COUNT; )
{
code = RandomCode();
if (!vHashtable.Contains(code)) // 避免重复
{
vHashtable.Add(code, null);
Array.Copy(code, 0, codeBuffer, i * 14, code.Length);
i++;
}
}
FileStream vFileStream = new FileStream(@"c:\temp\temp.txt",
FileMode.Create, FileAccess.Write);
int vPos = 0;
for (; vPos + 0x1000 < codeBuffer.Length; vPos += 0x1000)
{
vFileStream.Write(codeBuffer, vPos, 0x1000); // 减少文件写入的次数,采用每4096字节写一次。
}
vFileStream.Write(codeBuffer, vPos, codeBuffer.Length - vPos);
vFileStream.Close();
Console.WriteLine("耗时:{0}毫秒", Environment.TickCount - vTickCount);
}
关键的地方两点:1、不要频繁分配内存。2、不要频繁读写文件。
至于用hash表判断本身并不能起到关键性的提高。
这一句错了,code是每一次返回的byte[]实例,每次实例都不同,数组比较是引用比较,所以,vHashtable.Contains(code)不可能返回true
多谢提醒,测试的结果正如你所述,这个判断是错误的。
用List、Directory也不能判断出byte[]的内容。
转成string类型测试后可行。修改后的代码如下:
using System.Collections;private const int CODE_COUNT = 50000; // 记录数
private byte[] codeBuffer = new byte[14 * CODE_COUNT];private Random random = new Random();
public byte[] RandomCode()
{
byte[] vReturn = new byte[14];
vReturn[12] = 13;
vReturn[13] = 10;
for (int i = 0; i < 4; i++)
vReturn[i] = (byte)('A' + random.Next(26));
for (int i = 4; i < 12; i++)
vReturn[i] = (byte)('0' + random.Next(10));
return vReturn;
}private Dictionary<string, int> codeList = new Dictionary<string, int>();private void button1_Click(object sender, EventArgs e)
{
long vTickCount = Environment.TickCount;
codeList.Clear();
byte[] vCode = RandomCode();
for (int i = 0; i < CODE_COUNT; )
{
vCode = RandomCode();
string S = BitConverter.ToString(vCode);
if (!codeList.ContainsKey(S)) // 避免重复
{
codeList.Add(S, i);
Array.Copy(vCode, 0, codeBuffer, i * 14, vCode.Length);
i++;
}
}
FileStream vFileStream = new FileStream(@"c:\temp\temp.txt",
FileMode.Create, FileAccess.Write);
vFileStream.Write(codeBuffer, 0, codeBuffer.Length); // 内核会优化
vFileStream.Close();
Console.WriteLine("耗时:{0}毫秒", Environment.TickCount - vTickCount);
}
这样就可以放弃字典对byte[]或字符串的引用,对固定长度的字符串而言,RandomCode()可以改造为
void RandomCode(ref byte[] code)
进一步避免对byte[]的重复实例化,提高性能
为什么要执行两次啊?
最上面的code+= 也可以考虑改用StringBuilder. 并初始化一定的capacity.
using System;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;namespace ConsoleApplication5
{
class Program
{
private const int CODE_COUNT = 50000; // 记录数
private static readonly byte[] NewLine ={ 13, 10 };
private static Random random = new Random(); static void Main(string[] args)
{
Console.Write("Press Enter to start:");
Console.ReadLine();
Stopwatch sw = Stopwatch.StartNew();
using (FileStream fs = new FileStream("test.txt", FileMode.Create, FileAccess.Write))
using (BinaryWriter bw = new BinaryWriter(fs))
Exec(bw);
sw.Stop();
Console.WriteLine("耗时:{0}毫秒", sw.ElapsedMilliseconds);
Console.ReadLine();
} public static void RandomCode(ref byte[] buffer)
{
for (int i = 0; i < 4; i++)
buffer[i] = (byte)('A' + random.Next(26));
for (int i = 4; i < 12; i++)
buffer[i] = (byte)('0' + random.Next(10));
} private static void Exec(BinaryWriter bw)
{
Dictionary<int, int> codes = new Dictionary<int, int>(CODE_COUNT);
byte[] buffer = new byte[12];
int count = 0;
while (count < CODE_COUNT)
{
RandomCode(ref buffer);
int hash = Hash(buffer);
if (!codes.ContainsKey(hash))
{
codes.Add(hash, 0);
bw.Write(buffer);
bw.Write(NewLine);
count++;
}
}
} private static int Hash(byte[] buffer)
{
return BitConverter.ToInt32(buffer, 0) ^
BitConverter.ToInt32(buffer, 4) ^
BitConverter.ToInt32(buffer, 8);
} }
}
string+ 写成 StringBuilder.Append("").....性能最少优化5倍!
using System.Collections;private const int CODE_COUNT = 50000; // 记录数private Random random = new Random();
public byte[] RandomCode()
{
byte[] vReturn = new byte[14];
vReturn[12] = 13;
vReturn[13] = 10;
for (int i = 0; i < 4; i++)
vReturn[i] = (byte)('A' + random.Next(26));
for (int i = 4; i < 12; i++)
vReturn[i] = (byte)('0' + random.Next(10));
return vReturn;
}private Dictionary<string, int> codeList = new Dictionary<string, int>();private void button1_Click(object sender, EventArgs e)
{
long vTickCount = Environment.TickCount;
codeList.Clear();
byte[] vCode;
FileStream vFileStream = new FileStream(@"c:\temp\temp.txt",FileMode.Create, FileAccess.Write);
for (int i = 0; i < CODE_COUNT; )
{
vCode = RandomCode();
string S = BitConverter.ToString(vCode);
if (!codeList.ContainsKey(S)) // 避免重复
{
codeList.Add(S, i);i++;
vFileStream.Write(codeBuffer, 0, codeBuffer.Length); //这样更快,因为本身有循环
}
}
vFileStream.Close();
Console.WriteLine("耗时:{0}毫秒", Environment.TickCount - vTickCount);
}
看来FileStream本身也有内存缓冲机制
不过楼主好像失踪了。。
vwxyzh
的方法确实比较快
非常感谢各位的参与,以及几位提出解决方法的朋友~~