2010-06-28 2 views
2

поэтому возникла новая проблема ...C# Многопоточный проверщик прокси

Я пишу многопоточный прокси-чекер в 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 - это объект, который используется только для блокировки)

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

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

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

Спасибо :)

ответ

1

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

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

Спасибо, действительно красивое решение. И спасибо всем остальным за вашу помощь, я очень ценю это, но, к сожалению, я могу принять только один ответ. Проблема с «потерянными» прокси решена сейчас, я думаю. – Chilln

2

Пару вещей:

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

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

4

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

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

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

В принципе, если вы хотите, чтобы защитить доступ к структуре данных, с замком, убедитесь, что вы храните все операции чтения и записи в этой структуре для безопасности потоков.

2

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

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 - это объект, для которого вы хотите заблокировать доступ, просто используйте его.

+1

«Кроме того, вы действительно не нужен объект lockqueue - поскольку очередь это объект, который вы хотите заблокировать доступ, просто использовать Это." - Не делай этого; вместо этого заблокируйте отдельный экземпляр объекта. Это защита от других авторов классов, которые могут использовать 'lock (this)' внутренне. –

+0

@Tim Robinson: 'lock (this)' будет считаться плохой практикой программирования (http://msdn.microsoft.com/en-us/library/c5kehkcz(VS.80).aspx), и я сомневаюсь, что авторы из 'List' сделал бы это. – MusiGenesis

+0

Подробнее от MSDN: «Строго говоря, объект, предоставленный для блокировки, используется исключительно для уникальной идентификации ресурса, который используется для нескольких потоков, поэтому он может быть произвольным экземпляром класса. На практике, однако, этот объект обычно представляет собой ресурс, для которого необходима синхронизация потоков ". – MusiGenesis