我需要优化计算pos / neg值的代码并按时间删除不合格的值。
我有附加时间戳的值队列。
我需要丢弃1ms的值并计算负值和正值。这里是伪代码
list<val> l;
v = q.dequeue();
deleteold(l, v.time);
l.add(v);
negcount = l.count(i => i.value < 0);
poscount = l.count(i => i.value >= 0);
if(negcount == 10) return -1;
if(poscount == 10) return 1;
我需要在c#中以最大速度运行此代码。无需坚持清单。事实上,欢迎以neg和pos值分隔的数组。
编辑:可能不安全的数组将是最好的。任何提示?
编辑:感谢您的抬头.. 我快速测试了阵列版本与列表(我已经拥有)并且列表更快:35 vs 16 ms,1 mil迭代... < / p>
这是公平的代码:
class Program
{
static int LEN = 10;
static int LEN1 = 9;
static void Main(string[] args)
{
Var[] data = GenerateData();
Stopwatch sw = new Stopwatch();
for (int i = 0; i < 30; i++)
{
sw.Reset();
ArraysMethod(data, sw);
Console.Write("Array: {0:0.0000}ms ", sw.ElapsedTicks / 10000.0);
sw.Reset();
ListMethod(data, sw);
Console.WriteLine("List: {0:0.0000}ms", sw.ElapsedTicks / 10000.0);
}
Console.ReadLine();
}
private static void ArraysMethod(Var[] data, Stopwatch sw)
{
int signal = 0;
int ni = 0, pi = 0;
Var[] n = new Var[LEN];
Var[] p = new Var[LEN];
for (int i = 0; i < LEN; i++)
{
n[i] = new Var();
p[i] = new Var();
}
sw.Start();
for (int i = 0; i < DATALEN; i++)
{
Var v = data[i];
if (v.val < 0)
{
int x = 0;
ni = 0;
// time is not sequential
for (int j = 0; j < LEN; j++)
{
long diff = v.time - n[j].time;
if (diff < 0)
diff = 0;
// too old
if (diff > 10000)
x = j;
else
ni++;
}
n[x] = v;
if (ni >= LEN1)
signal = -1;
}
else
{
int x = 0;
pi = 0;
// time is not sequential
for (int j = 0; j < LEN; j++)
{
long diff = v.time - p[j].time;
if (diff < 0)
diff = 0;
// too old
if (diff > 10000)
x = j;
else
pi++;
}
p[x] = v;
if (pi >= LEN1)
signal = 1;
}
}
sw.Stop();
}
private static void ListMethod(Var[] data, Stopwatch sw)
{
int signal = 0;
List<Var> d = new List<Var>();
sw.Start();
for (int i = 0; i < DATALEN; i++)
{
Var v = data[i];
d.Add(new Var() { time = v.time, val = v.val < 0 ? -1 : 1 });
// delete expired
for (int j = 0; j < d.Count; j++)
{
if (v.time - d[j].time < 10000)
d.RemoveAt(j--);
else
break;
}
int cnt = 0;
int k = d.Count;
for (int j = 0; j < k; j++)
{
cnt += d[j].val;
}
if ((cnt >= 0 ? cnt : -cnt) >= LEN)
signal = 9;
}
sw.Stop();
}
static int DATALEN = 1000000;
private static Var[] GenerateData()
{
Random r = new Random(DateTime.Now.Millisecond);
Var[] data = new Var[DATALEN];
Var prev = new Var() { val = 0, time = DateTime.Now.TimeOfDay.Ticks};
for (int i = 0; i < DATALEN; i++)
{
int x = r.Next(20);
data[i] = new Var() { val = x - 10, time = prev.time + x * 1000 };
}
return data;
}
class Var
{
public int val;
public long time;
}
}
答案 0 :(得分:3)
要获得negcount和poscount,您将遍历整个列表两次。 相反,遍历它一次(计算negcount),然后poscount = l.Count - negcount。
答案 1 :(得分:1)
一些想法:
max(negcount,poscount)
变为10之前计数,然后退出(不需要计算其余部分)。仅当10是最大计数时才有效。negcount
并从count-negcount推断poscount,这比计算它们更容易。它们中的任何一个是否比现在更快,哪个更快,取决于数据通常的样子。是长吗?短?
更多关于3:
您可以使用欺骗来避免分支。您不必测试该项目是否为负数,您可以将其否定性添加到计数器中。假设该项为x
并且它是int
,则x >> 31
对于正x为0,对于负x为-1。因此counter -= x >> 31
会给negcount
。
编辑:不安全的数组可以更快,但不应该在这种情况下,因为循环的形式是
for (int i = 0; i < array.Length; i++)
do something with array[i];
由JIT编译器优化。