#c# #asp.net
#c# #asp.net
Вопрос:
Предположим, у меня есть статический вспомогательный класс, который я часто использую в веб-приложении. Предположим, что приложение получает около 20 запросов в секунду в течение длительного периода времени и что, как по волшебству, два запроса просят статический класс выполнить некоторую работу в одну и ту же наносекунду.
Что происходит, когда это происходит?
Чтобы обеспечить некоторый контекст, класс используется для выполнения запроса linq-to-sql: он получает несколько параметров, включая идентификатор пользователя, и возвращает список пользовательских объектов.
Спасибо.
Комментарии:
1. непреодолимая сила останавливается, и неподвижный объект перемещается
Ответ №1:
Это полностью зависит от того, что означает ваша «некоторая работа». Если это не связано с каким-либо общим состоянием, все в порядке. Если для этого требуется доступ к общему состоянию, вам нужно решить, как справиться с этим потокобезопасным способом.
Общее эмпирическое правило заключается в том, что общедоступный API класса должен быть потокобезопасным для статических методов, но не обязательно должен быть потокобезопасным для методов экземпляра — обычно любой экземпляр используется только в одном потоке. Конечно, это зависит от того, что делает ваш класс, и что вы подразумеваете под потокобезопасностью.
Комментарии:
1. Я использую класс для запроса linq-to-sql; это плохая идея? Не должен ли класс быть статическим и создаваться для каждого использования?
2. @frenchie: это довольно расплывчатый термин — прочитайте связанный пост в блоге. Но в ручных терминах это означает, что «плохих вещей не произойдет, если несколько потоков одновременно вызовут один и тот же код» в каком-то конкретном контексте.
3. @frenchie: сам Linq2SQL DataContext не является потокобезопасным. Пока каждый вспомогательный вызов инициализирует свой собственный контекст, и у вас нет доступа к другим статически разделяемым ресурсам, все должно быть в порядке
4. @frenchie: вы должны создать новую ссылку на SQL DataContext в методе , не сохраняя его в статической переменной. Есть ли у вас какие-либо переменные, которые являются общими для нескольких потоков? (Какие статические переменные у вас есть?)
5. Да, класс создает новый datacontext внутри. Я решил изменить класс со статического на создание экземпляра объекта внутри вызывающего класса. То есть, позже наверняка не будет никаких ошибок oooopsss.
Ответ №2:
Что происходит, когда это происходит?
Если ваши методы являются реентерабельными, то они потокобезопасны, и что произойдет, так это то, что, скорее всего, они будут работать. Если эти статические методы полагаются на какое-то общее состояние, и вы не синхронизировали доступ к этому состоянию, скорее всего, это общее состояние будет повреждено. Но вам не нужно запускать метод в одну и ту же наносекунду на 20 запросов, чтобы повредить ваше общее состояние. 2 в значительной степени достаточно, если вы не синхронизируете его.
Таким образом, статические методы сами по себе не являются злом (ну, на самом деле они таковы, поскольку они не подходят для модульного тестирования, но это уже другая тема), в многопоточной среде имеет значение то, как они реализованы. Поэтому вы должны сделать их потокобезопасными.
Обновить:
Поскольку в разделе комментариев вы упомянули LINQ-TO-SQL, пока все переменные, используемые в статическом методе, являются локальными, этот метод потокобезопасен. Например:
public static SomeEntity GetEntity(int id)
{
using (var db = new SomeDbContext())
{
return db.SomeEntities.FirstOrDefault(x => x.Id == id);
}
}
Комментарии:
1. Статический класс используется для запроса linq-to-sql. Плохая идея?
2. @frenchie, пока этот статический класс не использует статические ресурсы, которые не являются потокобезопасными, все должно быть в порядке.
3. @frenchie, я обновил свой ответ, чтобы привести пример потокобезопасного метода, который можно использовать с Linq-To-SQL.
4. Хорошо, круто, вот как написан мой класс. Если я хочу быть в безопасности, должен ли я потратить 10-15 минут и преобразовать в создание экземпляра класса?
5. @frenchie, да, вам потребуется 10-15 минут, чтобы преобразовать это в нестатический класс, который вы бы поместили в свой уровень DAL. Но вы должны делать это не потому, что эта реализация небезопасна. Вы должны сделать это, чтобы ослабить связь между вызывающим кодом и кодом доступа к данным.
Ответ №3:
вы должны убедиться, что ваши методы потокобезопасны, поэтому не используйте статические атрибуты для хранения какого-либо состояния. Если вы объявляете новые объекты внутри статического метода, проблем нет, потому что у каждого потока есть свой собственный объект.
Комментарии:
1. если два или более потоков выполняют метод одновременно, вам необходимо обеспечить контроль доступа к общим ресурсам, в противном случае вы получите неожиданное поведение. Это своего рода резюме поточно-безопасного термина
Ответ №4:
Это зависит от того, имеет ли статический класс какое-либо состояние или нет (т. Е. Статические переменные, общие для всех вызовов). Если это не так, то все в порядке. Если это так, это нехорошо. Примеры:
// Fine
static class Whatever
{
public string DoSomething() {
return "something";
}
}
// Death from above
static class WhateverUnsafe
{
static int count = 0;
public int Count() {
return count;
}
}
Вы можете заставить второй работать нормально, используя блокировки, но тогда вы вводите взаимоблокировки и проблемы с параллелизмом.
Я создавал массивные веб-приложения со статическими классами, но у них никогда не было общего состояния.
Комментарии:
1. Хорошо; Я использую статический класс для запроса linq-to-sql. Я облажался, если сделаю это? Я думал, что, сохраняя класс статическим, я экономлю затраты на создание экземпляра объекта.
2. Я сомневаюсь, что вам придется беспокоиться о стоимости создания экземпляра объекта. Это не дорого, плюс я не уверен, что Linq2SQL потокобезопасен.
Ответ №5:
Он выходит из строя неприятным образом (если вы делаете это для совместного использования состояния), избегайте делать это в веб-приложении… Или альтернативно защитить чтение / запись блокировкой:
http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx
Но, честно говоря, вам действительно следует избегать использования статики, если только вам ДЕЙСТВИТЕЛЬНО не нужно, и если вам действительно нужно, вы должны быть очень осторожны со своей стратегией блокировки и проверить ее на уничтожение, чтобы убедиться, что вам удалось изолировать операции чтения и записи друг от друга
Комментарии:
1. Кто сказал что-нибудь о чтении и записи? Нет никаких доказательств того, что при этом используется какое- либо общее состояние.
2. @Jon: Предположение — опасная вещь; p Я предполагал, что OP делает это, чтобы разделить состояние между потоками. Я обновил свой пост, чтобы отразить это так же, как вы опубликовали свой комментарий.