Впоследствии добавьте задачи к задаче, но ограничьте количество параллельно выполняемых - PullRequest
0 голосов
/ 25 октября 2018

У меня серьезные проблемы с производительностью, т.е. четыре ядра работают на 100%, блокируя все остальное, когда я хочу показать миниатюры в сетке, содержащей более 10 тыс. Записей.
При отображении строки возникает событиепользователю, который загружает изображение.В этом случае экземпляр GridImageManager вызывается с AddAndStartLoading.Когда я прокручиваю вниз, это событие запускается слишком часто, и мои ядра заполнены потоками.

Я пытался переписать код, используя Callbacks и список еще для загрузки ячеек, но этот список не является потокобезопасным, что приводит к исключениям, когда я хочу удалить элемент, который уже был удален из другогоthread.

Затем я попытался использовать семафоры, но с ними я не могу реализовать WaitForLoadingCompleted -метод, потому что не могу получить доступ к количеству свободных ресурсов.

Я также прочитал вЗадачи, но не могли понять, как они мне помогут.

Мои ограничения следующие:

  • Загрузка изображений должна начаться сразу же после первого вызова AddAndStartLoading.
  • В любой момент должно выполняться не более N процессов загрузки.
  • Последующие вызовы AddAndStartLoading могут ждать, но должны быть обработаны, как только количество процессов загрузки упадет ниже N.
  • WaitForLoadingCompleted должен дождаться окончания загрузки всех потоков, в то время как, с другой стороны, разрешено делать Application.DoEvents().Я не могу рефакторировать это в данный момент.

Какие шаблоны / стратегии я должен использовать для достижения этой цели?

Чтобы дать вам идею: это моя первая попытка.Это работает до точки, где CellsToLoad становится пустым.

public class GridImageManager
{

    public GridImageManager()
    {
        CellsToLoad = new List<(UltraGridCell cell, ImageLoader loader)>();
        LoadingCells = new Dictionary<UltraGridCell, ImageLoader>();
    }

    public delegate void ImageLoader(object obj);

    private List<(UltraGridCell cell, ImageLoader loader)> CellsToLoad { get; set; }

    private Dictionary<UltraGridCell, ImageLoader> LoadingCells { get; set; }

    public void AddCellToLoad(UltraGridCell cell, ImageLoader loader)
    {
        CellsToLoad.Add((cell, loader));

        StartLoading();
    }

    private void CallbackImageLoaded(IAsyncResult ar)
    {
        if (ar.AsyncState is UltraGridCell cell)
        {
            LoadingCells.Remove(cell);
            StartLoading();
        }
    }

    private void StartLoading()
    {
        if (LoadingCells.Count >= 10)
            return;

        if (CellsToLoad.Count == 0)
            return;

        var next = CellsToLoad.First();
        CellsToLoad.Remove(next);

        LoadingCells.Add(next.cell, next.loader);

        next.loader.BeginInvoke(null, CallbackImageLoaded, next.cell);
    }

    public void WaitForLoadingCompleted()
    {
        while (CellsToLoad.Count > 0 && LoadingCells.Count > 0)
        {
            Application.DoEvents(); // Can't refactor this right now
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...