简体   繁体   English

C#-锁不起作用,但易失性和锁可以吗?

[英]C# - Lock not working but Volatile AND Lock does?

I am trying to poll an API as fast and as efficiently as possible to get market data. 我正在尝试尽可能快和高效地轮询API以获取市场数据。 The API allows you to get market data from batchSize markets per request. 该API允许您根据请求从batchSize市场获取市场数据。 The API allows you to have 3 concurrent requests but no more (or throws errors). 该API允许您有3个并发请求,但没有更多(或引发错误)。

I may be requesting data from many more than batchSize different markets. 我可能要从不止批次大小的不同市场中请求更多数据。

I continuously loop through all of the markets, requesting the data in batches, one batch per thread and 3 threads at any time. 我不断遍历所有市场,分批请求数据,每个线程一个批处理,并随时请求3个线程。

The total number of markets (and hence batches) can change at any time. 市场总数(因此是批次)可以随时更改。

I'm using the following code: 我正在使用以下代码:

private static object lockObj = new object();

private void PollMarkets()
{
    const int NumberOfConcurrentRequests = 3;

    for (int i = 0; i < NumberOfConcurrentRequests; i++)
    {
        int batch = 0;
        Task.Factory.StartNew(async () =>
        {    
            while (true)
            {
                if (markets.Count > 0)
                {
                    List<string> batchMarketIds;

                    lock (lockObj)
                    {
                        var numBatches = (int)Math.Ceiling((double)markets.Count / batchSize);
                        batchMarketIds = markets.Keys.Skip(batch*batchSize).Take(batchSize).ToList();
                        batch = (batch + 1) % numBatches;
                    }

                    var marketData = await GetMarketData(batchMarketIds);

                    // Do something with marketData

                    }
                    else
                    {
                        await Task.Delay(1000); // wait for some markets to be added.
                    }
                }
            }
       });
    }
}

Even though there is a lock in the critical section, each thread starts with batch = 0 (each thread is often polling for duplicate data). 即使关键部分有锁,每个线程也都以batch = 0开始(每个线程通常轮询重复数据)。

If I change batch to a private volatile field the above code works as I want it to (volatile and lock). 如果我将批处理更改为私有volatile字段,则上面的代码可以按我希望的方式工作(volatile和锁定)。

So for some reason my lock doesn't work? 出于某种原因,我的锁不起作用? I feel like it's something obvious but I'm missing it. 我觉得这很明显,但是我很想念它。

I believe that it is best here to use a lock instead of a volatile field, is this also correct? 我相信最好在这里使用锁而不是volatile字段,这也正确吗?

Thanks 谢谢

The issue was that you were defining the batch variable inside the for loop. 问题是您正在for循环中定义批处理变量。 That meant that the threads were using their own variable instead of sharing it. 这意味着线程正在使用自己的变量,而不是共享它。

In my mind you should use Queue<> to create a jobs pipeline. 在我看来,您应该使用Queue <>创建作业管道。

Something like this 像这样

private int batchSize = 10;
private Queue<int> queue = new Queue<int>();

private void AddMarket(params int[] marketIDs)
{
    lock (queue)
    {
        foreach (var marketID in marketIDs)
        {
            queue.Enqueue(marketID);
        }

        if (queue.Count >= batchSize)
        {
            Monitor.Pulse(queue);
        }
    }
}

private void Start()
{
    for (var tid = 0; tid < 3; tid++)
    {
        Task.Run(async () =>
        {
            while (true)
            {
                List<int> toProcess;

                lock (queue)
                {
                    if (queue.Count < batchSize)
                    {
                        Monitor.Wait(queue);
                        continue;
                    }

                    toProcess = new List<int>(batchSize);
                    for (var count = 0; count < batchSize; count++)
                    {
                        toProcess.Add(queue.Dequeue());
                    }

                    if (queue.Count >= batchSize)
                    {
                        Monitor.Pulse(queue);
                    }
                }

                var marketData = await GetMarketData(toProcess);
            }
        });
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM