我正在计算经常变化的股票市场指数,所以我决定给我的服务器(运行 2 * E5-2640)单独的“核心”(24 个虚拟可用核心之一),因为到目前为止我只有 5% CPU 负载,所以我有很多可用的空闲 CPU 电源。
由于我需要尽快对股市指数变化做出反应,我决定使用无锁代码。这是我将在现实生活中使用的示例:
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace TestBlockingCollection2
{
class Program
{
static void Main(string[] args)
{
Stopwatch sw = Stopwatch.StartNew();
int i = 0;
Task.Factory.StartNew(() =>
{
while (true)
{
Console.WriteLine("Adding " + (i + 1));
sw = Stopwatch.StartNew();
i++;
Thread.Sleep(1000);
}
}, TaskCreationOptions.LongRunning);
Task.Factory.StartNew(() =>
{
int prevI = 0;
while (true)
{
if (prevI < i)
{
sw.Stop();
long microseconds = sw.ElapsedTicks / (Stopwatch.Frequency / (1000L * 1000L));
Console.WriteLine("Received " + i + ". Spent " + microseconds + " microseconds.");
prevI = i;
}
}
}, TaskCreationOptions.LongRunning);
while (true)
{
Thread.Sleep(1000);
}
}
}
}
输出:
C:\bin\testBlockingCollection2>TestBlockingCollection2.exe
Adding 1
Received 1. Spent 1 microseconds.
Adding 2
Received 2. Spent 5 microseconds.
Adding 3
Received 3. Spent 2 microseconds.
Adding 4
Received 4. Spent 2 microseconds.
Adding 5
Received 5. Spent 2 microseconds.
Adding 6
Received 6. Spent 4 microseconds.
Adding 7
Received 7. Spent 2 microseconds.
Adding 8
Received 8. Spent 2 microseconds.
Adding 9
Received 9. Spent 5 microseconds.
Adding 10
Received 10. Spent 2 microseconds.
Adding 11
Received 11. Spent 2 microseconds.
Adding 12
Received 12. Spent 2 microseconds.
Adding 13
Received 13. Spent 2 microseconds.
Adding 14
Received 14. Spent 2 microseconds.
Adding 15
Received 15. Spent 2 microseconds.
Adding 16
Received 16. Spent 3 microseconds.
Adding 17
Received 17. Spent 5 microseconds.
Adding 18
Received 18. Spent 2 microseconds.
Adding 19
Received 19. Spent 2 microseconds.
与我使用BlockingCollection
异步执行方法比 BlockingCollection 更好的 18 微秒相比,平均有 2 微秒是相当惊人的?
我真的很想要这个微秒,因为我有很多空闲的 CPU 能力,而且在 HFT 中微秒很重要。
所以这个问题很简单——你看到我的例子有什么问题吗?我从来没有写过无锁代码,所以我想我可能会犯愚蠢的错误。我不使用自旋锁,因为我假设原始更改(int/double/decimal)是“原子的”,所以在第二个线程中,我总是收到以前的或新的值,但没有别的。
即,如果在一个线程中我将 int x 从 100 更改为 555,那么在第二个线程中我将拥有 100 或 555,但绝不会是 500 或 155 或其他任何值。