Очевидное состояние гонки / проблема параллелизма - PullRequest
0 голосов
/ 03 января 2019

У меня есть веб-приложение, написанное с использованием ASP.NET MVC (C #), Entity Framework и базы данных Oracle.В одном из контроллеров у меня есть код, подобный следующему (урезанный, чтобы показать только то, что я считаю необходимым для этого вопроса):

    using (var context = CreateContext())
    {
        //Other code ...
        var workItem = //Get work item from context

        var nextReviewers =
            await context.WorkItemReviewers
                         .Where(r => r.WorkItemId == workItem.Id)
                         .Where(r => r.Position > workItem.NextReviewerPosition)
                         .OrderBy(r => r.Position)
                         .ToArrayAsync();
        if (nextReviewers.Count() > 0)
        {
            workItem.Status = "A";
            workItem.StatusDetails = "A";
            workItem.NextReviewerPosition = nextReviewers.First().Position;

            //Other Code
        }
        else
        {
            workItem.Status = "B";
            workItem.StatusDetails = "B";
            workItem.NextReviewerPosition = null;
        }

        //Other Code

        await context.SaveChangesAsync();
    }

Исходя из кода выше, я никогда ожидаю, что значения Status или StatusDetails будут когда-либо разными, но у меня есть ситуация, когда два запроса разошлись примерно на 3-4 миллисекунды, и теперь, необъяснимо , в базе данных есть следующие значения: Status= "B";StatusDetails = "A".

Я что-то упустил?Есть ли логическое объяснение этому на основе того, как EntityFramework (против Oracle 11g) может вести себя в ASP.NET?

1 Ответ

0 голосов
/ 07 января 2019

На основании приведенного выше кода, учитывая, что обновленный объект workItem был загружен в рамках контекста БД и что эти 2 значения являются строками, я должен сказать с уверенностью 99,5%, что этот код не отвечает заповедение, которое вы видите.(хотя я определенно буду наблюдать за этим пунктом, чтобы увидеть, доказано ли, что это неправильно :) Я бы внимательно посмотрел везде, где используются Status или StatusDetails в отношении вызовов, сделанных в службу.Я подозреваю, что какой-то другой код неожиданно меняет один или другой и вызывает SaveChanges.

Небольшая оптимизация, которую я могу предложить:

var nextReviewer = context.WorkItemReviewers
    .Where(r => r.WorkItemId == workItem.Id
        && r.Position > workItem.NextReviewerPosition)
    .OrderBy(r => r.Position)
    .Select(r => new { r.Position }) // Add any other details you may need from reviewer and other related entities.
    .FirstOrDefault();

if (nextReviewer != null)
{
    workItem.Status = "A";
    workItem.StatusDetails = "A";
    workItem.NextReviewerPosition = nextReviewer.Position;
    //Other Code
}
else
{
    workItem.Status = "B";
    workItem.StatusDetails = "B";
    workItem.NextReviewerPosition = null;
}

Используя .Select(), вы можете оптимизировать запрос доверните обратно столбцы из таблиц, которые вам нужны, что сделает вызовы в БД быстрее.Если не ожидается, что запрос будет относительно тяжелым с точки зрения времени (например,> ~ 500 мс), я бы также избегал асинхронной операции.Его цель - сделать сервер более отзывчивым при работе с большими операциями.Использование всего этого сделает все операции чуть медленнее, чем необходимо.После того, как вы оптимизировали возвращаемые данные, можно рассмотреть асинхронность, если все еще требуется некоторое время, чтобы прожевать.

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