Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从长字符串(300万个字符)读取大量(100万)子字符串(100个字符宽)_C#_String_Substring_Processing Efficiency - Fatal编程技术网

C# 从长字符串(300万个字符)读取大量(100万)子字符串(100个字符宽)

C# 从长字符串(300万个字符)读取大量(100万)子字符串(100个字符宽),c#,string,substring,processing-efficiency,C#,String,Substring,Processing Efficiency,在C#中,如何有效地从一个超过300万个字符的字符串中提取100万个子字符串?我写了一个程序,其中包括从一个300万字符的字符串中读取长度为100的随机DNA读取(随机位置的子字符串)。有100万这样的读者。目前,我运行了一个while循环,该循环运行了100万次,并从300万字符的字符串中读取了一个100字符长的子字符串。这需要很长时间。我可以做些什么来更快地完成这项工作 这是我的代码,len是原始字符串的长度,在本例中为300万,可能低至50,这就是while循环中检查的原因 while(i

在C#中,如何有效地从一个超过300万个字符的字符串中提取100万个子字符串?我写了一个程序,其中包括从一个300万字符的字符串中读取长度为100的随机DNA读取(随机位置的子字符串)。有100万这样的读者。目前,我运行了一个while循环,该循环运行了100万次,并从300万字符的字符串中读取了一个100字符长的子字符串。这需要很长时间。我可以做些什么来更快地完成这项工作

这是我的代码,len是原始字符串的长度,在本例中为300万,可能低至50,这就是while循环中检查的原因

while(i < 1000000 && len-100> 0) //len is 3000000
            {
                int randomPos = _random.Next()%(len - ReadLength);
                readString += all.Substring(randomPos, ReadLength) + Environment.NewLine;
                i++;


            }
while(i<1000000&&len-100>0)//len是3000000
{
int randomPos=_random.Next()%(len-ReadLength);
readString+=all.Substring(randomPos,ReadLength)+Environment.NewLine;
i++;
}

我认为会有更好的解决方案,但.NET StringBuilder类实例比字符串类实例更快,因为它将数据作为流处理

您可以将数据拆分为多个部分,并使用.NET任务并行库进行多线程和并行处理

编辑:为循环外的变量指定固定值,以避免重新计算

int x = len-100 
int y = len-ReadLength 
使用

为了实现并行性,您应该将输入拆分为多个部分。然后在单独的线程中运行这些操作。然后将结果合并

重要提示:根据我以前的经验,这些操作在.NET v2.0而不是v4.0中运行得更快,因此您应该更改您的项目目标框架版本;但您不能在.NETV2.0中使用任务并行库,所以您应该像以前那样使用多线程

Thread newThread ......

使用StringBuilder组装字符串将使处理增加600倍(因为它避免了每次附加到字符串时重复创建对象)

循环前(初始化容量可避免在StringBuilder中重新创建备份阵列):

循环中:

sb.Append(all.Substring(randomPos, ReadLength) + Environment.NewLine);
sb.Append(chars, randomPos, ReadLength);
sb.AppendLine();
循环后:

readString = sb.ToString();
使用char数组而不是字符串来提取值还可以提高30%,因为在调用Substring()时可以避免创建对象:

循环前:

char[] chars = all.ToCharArray();
循环中:

sb.Append(all.Substring(randomPos, ReadLength) + Environment.NewLine);
sb.Append(chars, randomPos, ReadLength);
sb.AppendLine();
编辑(不使用StringBuilder并以300ms执行的最终版本):

char[] chars = all.ToCharArray();    
var iterations = 1000000;
char[] results = new char[iterations * (ReadLength + 1)];    
GetRandomStrings(len, iterations, ReadLength, chars, results, 0);    
string s = new string(results);

private static void GetRandomStrings(int len, int iterations, int ReadLength, char[] chars, char[] result, int resultIndex)
{
    Random random = new Random();
    int i = 0, index = resultIndex;
    while (i < iterations && len - 100 > 0) //len is 3000000 
    {
        var i1 = len - ReadLength;
        int randomPos = random.Next() % i1;

        Array.Copy(chars, randomPos, result, index, ReadLength);
        index += ReadLength;
        result[index] = Environment.NewLine[0];
        index++;

        i++;
    }
}
char[]chars=all.tocharray();
var迭代次数=1000000;
字符[]结果=新字符[迭代次数*(ReadLength+1)];
GetRandomString(len、迭代次数、ReadLength、字符、结果,0);
字符串s=新字符串(结果);
私有静态void GetRandomStrings(int len、int迭代、int ReadLength、char[]chars、char[]result、int resultIndex)
{
随机=新随机();
int i=0,index=resultIndex;
而(i0)//len是3000000
{
var i1=len-读取长度;
int randomPos=random.Next()%i1;
复制(字符、随机位置、结果、索引、读取长度);
索引+=读取长度;
结果[索引]=环境.换行符[0];
索引++;
i++;
}
}

编辑:我放弃了使用memcpy的想法,我认为效果非常好。 我已经在43毫秒内把一根3米长的绳子分成了30k根100米长的绳子

private static unsafe string[] Scan(string hugeString, int subStringSize)
{
    var results = new string[hugeString.Length / subStringSize];

    var gcHandle = GCHandle.Alloc(hugeString, GCHandleType.Pinned);

    var currAddress = (char*)gcHandle.AddrOfPinnedObject();

    for (var i = 0; i < results.Length; i++)
    {
        results[i] = new string(currAddress, 0, subStringSize);
        currAddress += subStringSize;
    }

    return results;
}
private static unsafe string[]扫描(string hugeString,int subStringSize)
{
var results=新字符串[hugeString.Length/subStringSize];
var gcHandle=gcHandle.Alloc(hugeString,GCHandleType.pinted);
var currAddress=(char*)gcHandle.addrofpindedObject();
对于(var i=0;i
要使用问题中所示案例的方法:

const int size = 3000000;
const int subSize = 100;

var stringBuilder = new StringBuilder(size);
var random = new Random();

for (var i = 0; i < size; i++)
{
    stringBuilder.Append((char)random.Next(30, 80));
}

var hugeString = stringBuilder.ToString();

var stopwatch = Stopwatch.StartNew();
for (int i = 0; i < 1000; i++)
{
    var strings = Scan(hugeString, subSize);
}
stopwatch.Stop();

Console.WriteLine(stopwatch.ElapsedMilliseconds / 1000); // 43
const int size=3000000;
const int subSize=100;
var stringBuilder=新的stringBuilder(大小);
var random=新的random();
对于(变量i=0;i
长时间是多长?不应该那么长

var file = new StreamReader(@"E:\Temp\temp.txt");
var s = file.ReadToEnd();
var r = new Random();
var sw = new Stopwatch();
sw.Start();
var range = Enumerable.Range(0,1000000);
var results = range.Select( i => s.Substring(r.Next(s.Length - 100),100)).ToList();
sw.Stop();
sw.ElapsedMilliseconds.Dump();
s.Length.Dump();
在我的机器上,结果是807ms,字符串是4055442个字符

编辑:我刚刚注意到你想要一个字符串作为结果,所以我的上述解决方案只是更改为

var results = string.Join(Environment.NewLine,range.Select( i => s.Substring(r.Next(s.Length - 100),100)).ToArray());

加上大约100ms,所以总共还不到1秒。

你多久切换一次DNA链并读取一条新的DNA链?你正在读取的DNA链总数是否有一定数量?让DNA变小,也许是一个字节长如何?:-d是否应用多线程工作?你在随机位置读取DNA链?你不需要读取序列号g确定子字符串?首先使用比
字符串更节省空间的类型(每个位置确实需要2个字节吗?),但我怀疑真正让您慢下来的是
readString+=…
,它分配了一百万个新字符串,可能会导致垃圾收集器口处起泡。使用
String
而不是
readString
作为
readString
,而是使用
StringBuilder readString=new StringBuilder(ReadLength*numSubstrings);
,然后每次通过循环时,
readString.AppendLine(all.Substring…)
。您好,您能提供一些示例吗?添加了一些示例和更多定义。使用stringbuilder可以为我提供必要的性能增益。这项工作在几秒钟内完成!您需要小心地并行此代码,因为它使用的随机类不是线程安全的。如果您要走这条路,您应该查看这里建议的解决方案