C # Многопоточная проверка прокси - PullRequest
2 голосов
/ 28 июня 2010

Итак, возникла новая проблема ...

Я пишу многопоточный прокси-чекер в c #.

Я использую BackgroundWorkers для решения проблемы многопоточности.

Но у меня проблемы с координацией и назначением прокси, оставшихся в очереди, бегущим работникам. Он работает большую часть времени, но иногда результат не возвращается, поэтому некоторые прокси «теряются» во время процесса.

Этот список представляет очередь и заполняется идентификаторами прокси в ListView.

private List<int> queue = new List<int>();

private int GetNextinQueue() 
    {
        if(queue.Count > 0) 
        {
            lock (lockqueue)
            {
                int temp = queue[0];
                queue.Remove(temp);
                return temp;
            }
        }
        else 
            return -1;
    }

Выше приведен мой метод получения следующего прокси-сервера в очереди, я использую оператор блокировки, чтобы предотвратить состояние гонки, но я не уверен, достаточно ли этого или замедляет процесс, потому что заставляет другие потоки ждать ... (lockqueue - это объект, который используется только для блокировки)

Итак, мой вопрос: как это возможно, что некоторые прокси не проверяются (даже если проверка связи не проходит, проверка должна что-то возвращать, но иногда просто ничего) и как я могу оптимизировать этот код для производительности?

Вот остаток кода, который я считаю важным для этого вопроса http://pastebin.com/iJduX82b

Если чего-то не хватает, просто напишите комментарий

Спасибо:)

Ответы [ 4 ]

4 голосов
/ 28 июня 2010

Проверка для queue.Count должна выполняться в операторе блокировки.В противном случае вы можете проверить этот queue.Count> 0, но к тому времени, когда вы сможете войти в блокировку, другой поток мог удалить элемент из очереди, и тогда вы будете вызывать Remove в возможно пустой очереди.

Вы можете изменить его на:

private int GetNextinQueue() 
    {
        lock (lockqueue)
        {
            if(queue.Count > 0) 
            {
                int temp = queue[0];
                queue.Remove(temp);
                return temp;
            }
            else 
                return -1;
        }
    }

По сути, если вы хотите защитить доступ к структуре данных с помощью блокировки, убедитесь, что вы защищаете ВСЕ чтения и записи в эту структуру для потоковогобезопасность.

2 голосов
/ 28 июня 2010

Попробуйте вместо этого:

private int GetNextinQueue()  
{ 
    int ret = -1;
    lock (queue)
    {
        if (queue.Count > 0)  
        { 
            int temp = queue[0]; 
            queue.Remove(temp); 
            ret = temp; 
        } 
    } 
    return ret; 
}

Я не буду беспокоиться о производительности с этим - это правда, что другие потоки будут блокироваться здесь, если один поток удерживает блокировку, но удаляет int из списка.не занимает много времени.

Кроме того, вам действительно не нужен объект lockqueue - поскольку queue - это объект, к которому вы хотите заблокировать доступ, просто используйте его.

2 голосов
/ 28 июня 2010

Пара вещей:

  1. Все обращения к полю queue должны проходить внутри блока lock (lockqueue) - включая строку if (queue.Count > 0) выше. Это не вопрос производительности: ваше приложение не будет работать, если вы не получите блокировку там, где это необходимо.

  2. С вашей вставки вызов RunWorkerAsync выглядит подозрительно. В настоящее время каждый BackgroundWorker использует один и тот же массив аргументов; вам нужно дать каждому свою копию.

1 голос
/ 28 июня 2010

Если вас интересует простая элегантность, используйте очередь:

    private Queue<int> queue = new Queue<int>();
    private int GetNextinQueue()
    {
        lock (queue) { return queue.Count > 0 ? queue.Dequeue() : -1; }
    }
...