Побочные эффекты многопоточности в веб-сервисе ASMX - PullRequest
0 голосов
/ 23 ноября 2011

Я пытаюсь запустить SharePoint SPSiteDataQuery для всех веб-сайтов в семействе сайтов для коллекции списков. Среднее время получения данных со всех сайтов для одного списка [spWeb.GetSiteData(dataQuery)] составляет от 1 до 20 секунд. Коллекция списков может содержать практически любое количество списков.

Я реализовал логику потоков, как показано ниже. Но я получаю разное количество записей на каждый звонок. Я не очень опытен с многопоточной архитектурой. Что происходит, и стоит ли думать о лучшей архитектуре многопоточности?

private static Dictionary<string,string> _workTypes = new Dictionary<string, string>();
private static Dictionary<string,string> _workspaces = new Dictionary<string, string>();
private static List<string> _processedMyWorkItems = new List<string>(); 
private static readonly object Locker = new object();

var threads = new List<Thread>();
var processedMyWorkData = new Dictionary<string, List<XElement>>();

foreach (string selectedList in selectedLists.Distinct().OrderBy(l => l))
{
    string theSelectedList = selectedList;

    string listIds = string.Empty;

    foreach (string listId in GetListIdsFromDb(selectedList, spWeb, archivedWebs)
        .Where(listId => !selectedListIds.Contains(listId)))
    {
        selectedListIds.Add(listId);
        listIds += string.Format(@"<List ID='{0}'/>", listId);
    }

    if (string.IsNullOrEmpty(listIds)) continue;

    dataQuery.Lists = string.Format("<Lists MaxListLimit='0'>{0}</Lists>", listIds);

    var thread = new Thread(() =>
    {
        List<XElement> processedMyWork = ProcessMyWork(selectedFields, spSite, spWeb, dataQuery, fieldTypes);

        lock (Locker)
        {
            processedMyWorkData.Add(theSelectedList, processedMyWork);
        }
    }) { Name = theSelectedList };

    threads.Add(thread);
    thread.Start();
}

bool done = false;

while (!done)
{
    Thread.Sleep(500);

    bool noThreadIsAlive = true;
    var threadsCompleted = new List<Thread>();

    foreach (var thread in threads)
    {
        if (thread.IsAlive)
        {
            noThreadIsAlive = false;
        }
        else
        {
            threadsCompleted.Add(thread);
        }
    }

    foreach (var thread in threadsCompleted)
    {
        threads.Remove(thread);

        string key = thread.Name;
        foreach (var xElement in processedMyWorkData[key])
        {
            result.Element("MyWork").Add(xElement);
        }

        lock (Locker)
        {
            processedMyWorkData.Remove(key);
        }
    }

    done = noThreadIsAlive;
}

Ответы [ 2 ]

1 голос
/ 27 ноября 2011

Просто глядя на проблему с синхронизацией, вам нужно использовать WaitAll (), а не циклически повторять WaitOne () или опрашивать свойство IsAlive.Чтобы настроить его, вам понадобится событие для каждого потока, а затем добавьте его в массив основного потока, который будет использовать его для ожидания всех событий одновременно.Обратите внимание, что с помощью WaitAll () можно отслеживать не более 64 событий.

http://msdn.microsoft.com/en-us/library/3dasc8as(v=vs.80).aspx

0 голосов
/ 23 ноября 2011

static поля в сервисе ASMX (или, в этом отношении, в любом сервисе) существуют один раз для всего сервиса. Это означает, что если у вас есть два запроса, поступающих одновременно, они оба записывают один и тот же набор данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...