使用就绪堆栈的MultiThreading

时间:2015-02-13 18:22:16

标签: c# multithreading stack locking monitor

我遇到了导致性能问题的问题。我有一个地图应用程序,并且动态生成一些图块,其他图像被缓存并重试。两种方法都使用多线程。问题是,如果在运行中生成切片并且有大量数据需要检索,则存在性能问题。用户平移/缩放,应用程序必须查询信封中的所有内容,并在每次地图更改时返回图像。如果我锁定了动态生成磁贴的方法,那么缓存的文件会快速生成,但是如果用户平移和缩放很多,则生成动态磁贴需要花费很长时间。我的问题是:

有没有办法实现锁定,然后在方法完成后,访问就绪队列中的最后一个线程?我想我正在寻找的是一个就绪堆栈而不是一个就绪队列。这样,用户当前所在的区域将比以后更快地生成它。

我正在使用本地Web服务来生成切片。这是我到目前为止所拥有的。

1 个答案:

答案 0 :(得分:2)

您根本不需要使用任何锁定,只需使用线程安全堆栈实现(如System.Collections.Concurrent.ConcurrentStack)来保存要执行的工作队列。然后,您只需将工作线程池全部推送,或者单独从该堆栈中完成工作。

您可以使用Parallel.ForEach和阻止集合轻松地使用.NET 4.5实现整个工作队列系统。你没有提供任何代码,所以我不得不为一个例子做些什么,但它可以像这样工作。

public void StartTileProcessor()
{
    //The default for a BlockingCollection is a Queue, but you can pass in a stack for the underlying collection and it will behave as a stack.
    var stack = new BlockingCollection<UnprocessedTileMetadata>(new ConcurrentStack<UnprocessedTileMetadata>());

    var processorThread = Task.Run(() => ProcessTiles(stack));

    _yourGui.TileRequested += (sender, e) => stack.Add(e.RequestedTile);

    //...
}

/// <summary>
/// The method for processing tiles, takes from the stack and returns to the output.
/// </summary>
/// <param name="inputStack">The blocking collection that represents the input stack.</param>
private void ProcessTiles(BlockingCollection<UnprocessedTileMetadata> inputStack)
{
    //This is done so the foreach does not try to buffer requests from the consuming enumerable, the next item it processes will be the last added to the stack.
    var partitioner = Partitioner.Create(inputStack.GetConsumingEnumerable(), EnumerablePartitionerOptions.NoBuffering);
    Parallel.ForEach(partitioner, (unprocessedTile) =>
    {
        ProcessedTile tile = GenerateOrGetFromCache(unprocessedTile);
        _yourGui.SendToDisplay(tile);
    });
}