Выполнение задач параллельно в ASP.NET метод действия MVC 3

у меня есть действие поиска в ASP.NET MVC 3 приложение, которое возвращает предложения содержащих и предложения тегом с заданными ключевыми словами:

[HttpPost]
public ActionResult Search(string query, int pg = 0)
{
    var keywords = query.Split(new[] { ' ', ',', ';' }, 
        StringSplitOptions.RemoveEmptyEntries);

    var containing = (from s in _readonlySession.All<Suggestion>()
                      from k in keywords
                      where (s.Text.ToLower().Contains(k.ToLower()))
                      orderby s.Text
                      select s).Distinct();

    var tagged = (from t in _readonlySession.All<Tag>()
                  from s in t.Suggestions
                  from k in keywords
                  where t.Text.ToLower().Contains(k.ToLower())
                  orderby s.Text
                  select s).Distinct();

    var model = new SearchViewModel
    {
        Query = query,
        Containing = containing.ToList(),
        Tagged = tagged.ToList()
    };

    return View(model);
}

Я думаю containing и tagged запросы могут выполняться параллельно.

каков наилучший способ запустить эти два запроса одновременно, дождаться результатов и вернуться только после завершения обоих запросов?

3 ответов


библиотека задач Parallels-ваш лучший вариант. Много информации через Google, но ниже то, что ваша реализация может выглядеть.

[HttpPost]
public ActionResult Search(string query, int pg = 0)
{
    var keywords = query.Split(new[] { ' ', ',', ';' }, 
        StringSplitOptions.RemoveEmptyEntries);

    IEnumerable containing=null;
    Task t1 = Task.Factory.StartNew(() =>
    {
        containing = (from s in _readonlySession.All<Suggestion>()
                        from k in keywords
                        where (s.Text.ToLower().Contains(k.ToLower()))
                        orderby s.Text
                        select s).Distinct().ToList();

    });

    IEnumerable tagged=null;
    Task t2 = Task.Factory.StartNew(() =>
    {
        var tagged = (from t in _readonlySession.All<Tag>()
                        from s in t.Suggestions
                        from k in keywords
                        where t.Text.ToLower().Contains(k.ToLower())
                        orderby s.Text
                        select s).Distinct().ToList();
    });

    t1.Wait();
    t2.Wait();

    var model = new SearchViewModel
    {
        Query = query,
        Containing = containing.ToList(),
        Tagged = tagged.ToList()
    };

    return View(model);
}

имейте в виду, что если ваше приложение получает много запросов, вы можете быть лучше не выполнение ваших запросов асинхронно-потребляет 2 дополнительных потока для обслуживания одного запроса отнимает ресурсы от других входящих запросов. Это будет только проблема, если у вас огромный объем трафика, или если ваш аппаратное обеспечение неадекватно.


вы хотите быть осторожным, используя TPL из веб-страницы, поскольку TPL будет использовать потоки, которые в противном случае будут использоваться для обслуживания других HTTP-запросов. По сути, вы можете обменять более низкую задержку ответа на отдельные запросы на уменьшенную общую пропускную способность запросов.

см. Следующий пост для более подробного объяснения о компромиссах:

http://blogs.msdn.com/b/pfxteam/archive/2010/02/08/9960003.aspx


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

public class SearchController: AsyncController
{
    public void SearchAsync(string query, int pg = 0)
    {
        // TODO: Write a custom model binder to do this job
        // and have your controller action directly take an
        // IEnumerable<string> argument.
        var keywords = query.Split(new[] { ' ', ',', ';' }, 
            StringSplitOptions.RemoveEmptyEntries);

        AsyncManager.OutstandingOperations.Increment();
        AsyncManager.OutstandingOperations.Increment();

        _readonlySession.GetContainingCompleted += (sender, e) =>
        {
            AsyncManager.Parameters["containing"] = e.Value;
            AsyncManager.OutstandingOperations.Decrement();
        };

        _readonlySession.GetTaggedCompleted += (sender, e) =>
        {
            AsyncManager.Parameters["tagged"] = e.Value;
            AsyncManager.OutstandingOperations.Decrement();
        };

        _readonlySession.GetContainingAsync(keywords);
        _readonlySession.GetTaggedAsync(keywords);

        AsyncManager.Parameters["query"] = query;
    }

    public ActionResult SearchCompleted(string query, IEnumerable<Suggestion> containing, IEnumerable<Tag> tagged)
    {
        var model = new SearchViewModel
        {
            Query = query,
            Containing = containing.ToList(),
            Tagged = tagged.ToList()
        };
        return View(model);
    }
}