День 1724. #ЗаметкиНаПолях
Структурированный Параллелизм в C#
Структурированный параллелизм — это концепция, которая помогает писать более надёжный и удобный в обслуживании асинхронный код. Она не нова, но не так широко известна. Идея состоит в том, чтобы иметь возможность группировать асинхронные операции и гарантировать, что все операции завершатся до завершения группы. Это делается с помощью специальной конструкции, называемой областью задачи (Task Scope). Область задачи — это конструкция, похожая на блок try-catch-finally. Она используется для группировки асинхронных операций и обеспечения завершения всех операций до завершения группы.
Рассмотрим пример:
Идея в том, что мы определяем области в методе Create. Всё внутри Create будет выполняться в определённой области. Таким образом, задачи логически связаны друг с другом: если в одной выбрасывается исключение, мы отменяем все задачи вместе.
Использование:
Источник: https://steven-giesel.com/blogPost/59e57336-7c73-472f-a781-b0b79f0d47ad
Структурированный Параллелизм в C#
Структурированный параллелизм — это концепция, которая помогает писать более надёжный и удобный в обслуживании асинхронный код. Она не нова, но не так широко известна. Идея состоит в том, чтобы иметь возможность группировать асинхронные операции и гарантировать, что все операции завершатся до завершения группы. Это делается с помощью специальной конструкции, называемой областью задачи (Task Scope). Область задачи — это конструкция, похожая на блок try-catch-finally. Она используется для группировки асинхронных операций и обеспечения завершения всех операций до завершения группы.
Рассмотрим пример:
public class TaskScopeИзвините за много кода, но это только упрощённая реализация.
{
private CancellationTokenSource _cts = new();
private ConcurrentBag<Task> _tasks = new();
private TaskScope() { }
public static async Task Create(
Func<TaskScope, Task> act)
{
await using var ts = new TaskScope();
await act(ts);
await ts.WaitForAll();
}
public static async Task Create(
Action<TaskScope> act)
{
await using var ts = new TaskScope();
act(ts);
await ts.WaitForAll();
}
public async ValueTask DisposeAsync()
{
_cts.Cancel();
await WaitForAll();
}
public Task Run(
Func<CancellationToken, Task> act)
{
var task = Task.Run(async () =>
{
try
{
await act(_cts.Token);
}
catch (Exception ex) when (
ex is not OperationCanceledException)
{
_cts.Cancel();
throw;
}
});
_tasks.Add(task);
return task;
}
private async Task WaitForAll()
{
try
{
await Task.WhenAll(_tasks.ToArray());
}
catch (Exception ex) when (
ex is not OperationCanceledException)
{
throw;
}
}
}
Идея в том, что мы определяем области в методе Create. Всё внутри Create будет выполняться в определённой области. Таким образом, задачи логически связаны друг с другом: если в одной выбрасывается исключение, мы отменяем все задачи вместе.
Использование:
var tasks = TaskScope.Create(group =>Как видите, мы можем сгруппировать задачи и убедиться, что все они выполнены до того, как будет завершена область действия. Если одна из задач завершается сбоем, все остальные задачи отменяются и появляется исключение. Это очень мощная концепция, которая помогает писать более надёжный и удобный в обслуживании асинхронный код. Более сложную реализацию можно найти здесь.
{
group.Run(async token =>
{
await Task.Delay(100, token);
throw new Exception("Boom!!!");
});
group.Run(async token =>
await Task.Delay(1000, token));
});
// Выполняется 100мс
// после ошибки в 1й задаче отменяются все.
// Исключение поднимается наверх
try
{
await tasks;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
// True
Console.WriteLine(tasks.IsFaulted);
Источник: https://steven-giesel.com/blogPost/59e57336-7c73-472f-a781-b0b79f0d47ad
👍25
День 1725. #Оффтоп #Обучение
Запертые Двери, Головные Боли и Интеллектуальные Потребности
Есть ли такие вещи, узнав о которых, вы начинали их видеть повсюду? Это «проблема очерёдности проблемы и решения». Сегодня поговорим о ней.
Игры
Новичок начинает игру с тщательно продуманного учебного уровня. Уровень приводит его к ключу, который он берёт, а затем к запертой двери, которую он успешно открывает. Далее в игре он натыкается на вторую запертую дверь… и оказывается в тупике. Он уже однажды решал эту проблему – почему ему так трудно решить её снова?
Здесь мы имеем дело с проблемой очерёдности проблемы и решения. Поскольку игрок сначала получил ключ, а потом наткнулся на запертую дверь, он так и не понял причинно-следственной связи между «получить ключ» и «открыть дверь». Он получил ключ, потом произошло ещё что-то, а потом он достиг двери, которую смог открыть. Если бы игрок сначала столкнулся с запертой дверью, попытался открыть её, но не смог, а затем нашёл ключ и использовал его, чтобы открыть дверь, причинно-следственная связь была бы очевидной. Вы используете ключ, чтобы открыть запертую дверь, потому что вы не можете открыть запертую дверь без ключа.
Математика
Помните, как на уроке математики вам давали концепцию, потом ещё более сложную концепцию, а вам всё это казалась совершенно бессмысленным? Проблема в том, что, прежде чем предлагать вам новую, более сложную концепцию, вам не дали возможности испытать ограничения старой. Другими словами: если вам представят решение (новую концепцию) до того, как представят тип задач, которые оно должно решить, решение, скорее всего, покажется бессмысленным и произвольным.
Представьте себя человеком, который продаёт аспирин. Лучший покупатель вашего аспирина — тот, у кого болит голова. Худшее, что вы можете сделать, — заставить людей, которые не чувствуют боли, принимать ваш аспирин. Они могут это сделать, но аспирин покажется им бессмысленным.
Программирование
В функциональном программировании есть понятие монады. Они очень абстрактны, и новичкам часто сложно их понять. Но монады на самом деле не так уж и сложны. Большинство опытных функциональных программистов считают их простыми. Очевидно, всему виной проблема очерёдности проблемы и решения.
Монады — это решение конкретной проблемы: повторяющегося кода. Если вы пишете достаточно кода на функциональном языке, вы начинаете замечать, что пишете много подозрительно похожего кода для решения множества внешне разных задач. Было бы здорово, просто написать этот код один раз, а затем использовать его повторно, вместо того чтобы каждый раз переписывать его немного по-другому. То есть опытные функциональные программисты почувствовали головную боль, для которой монады являются аспирином. А новички ещё не заметили никаких повторяющихся закономерностей; или повторение их ещё не беспокоит. Головной боли просто нет.
Худшее, что вы можете сделать, — это заставить людей, которые не чувствуют боли, принимать аспирин. Точно так же попытка «обучить монадам» начинающих функциональных программистов, которые ещё не понимают необходимости в монадах, скорее всего, принесёт больше вреда, чем пользы, создавая дополнительную ненужную путаницу и увековечивая миф о том, что монады по своей сути сложны для понимания.
Итого
Строгая очерёдность проблем и решений является одним из определяющих фактором для эффективного понимания. Хорошо продуманный материал сразу же предлагает читателю поиграть с первоначальным расположением элементов и тем самым самостоятельно обнаружить потенциальные проблемы. Непосредственный опыт решения проблемы вызывает интеллектуальную потребность (или, если хотите, «головную боль») и создаёт основу для последующего внедрения решения. Поэтому лучшие обучающие материалы начинают с постановки проблемы, а не предлагают решение сразу. Но даже если это не так, изучая новую концепцию, придумайте (или погуглите), какую проблему она призвана решить. Это очень поможет пониманию и запоминанию.
Источник: https://mkremins.github.io/blog/doors-headaches-intellectual-need/
Запертые Двери, Головные Боли и Интеллектуальные Потребности
Есть ли такие вещи, узнав о которых, вы начинали их видеть повсюду? Это «проблема очерёдности проблемы и решения». Сегодня поговорим о ней.
Игры
Новичок начинает игру с тщательно продуманного учебного уровня. Уровень приводит его к ключу, который он берёт, а затем к запертой двери, которую он успешно открывает. Далее в игре он натыкается на вторую запертую дверь… и оказывается в тупике. Он уже однажды решал эту проблему – почему ему так трудно решить её снова?
Здесь мы имеем дело с проблемой очерёдности проблемы и решения. Поскольку игрок сначала получил ключ, а потом наткнулся на запертую дверь, он так и не понял причинно-следственной связи между «получить ключ» и «открыть дверь». Он получил ключ, потом произошло ещё что-то, а потом он достиг двери, которую смог открыть. Если бы игрок сначала столкнулся с запертой дверью, попытался открыть её, но не смог, а затем нашёл ключ и использовал его, чтобы открыть дверь, причинно-следственная связь была бы очевидной. Вы используете ключ, чтобы открыть запертую дверь, потому что вы не можете открыть запертую дверь без ключа.
Математика
Помните, как на уроке математики вам давали концепцию, потом ещё более сложную концепцию, а вам всё это казалась совершенно бессмысленным? Проблема в том, что, прежде чем предлагать вам новую, более сложную концепцию, вам не дали возможности испытать ограничения старой. Другими словами: если вам представят решение (новую концепцию) до того, как представят тип задач, которые оно должно решить, решение, скорее всего, покажется бессмысленным и произвольным.
Представьте себя человеком, который продаёт аспирин. Лучший покупатель вашего аспирина — тот, у кого болит голова. Худшее, что вы можете сделать, — заставить людей, которые не чувствуют боли, принимать ваш аспирин. Они могут это сделать, но аспирин покажется им бессмысленным.
Программирование
В функциональном программировании есть понятие монады. Они очень абстрактны, и новичкам часто сложно их понять. Но монады на самом деле не так уж и сложны. Большинство опытных функциональных программистов считают их простыми. Очевидно, всему виной проблема очерёдности проблемы и решения.
Монады — это решение конкретной проблемы: повторяющегося кода. Если вы пишете достаточно кода на функциональном языке, вы начинаете замечать, что пишете много подозрительно похожего кода для решения множества внешне разных задач. Было бы здорово, просто написать этот код один раз, а затем использовать его повторно, вместо того чтобы каждый раз переписывать его немного по-другому. То есть опытные функциональные программисты почувствовали головную боль, для которой монады являются аспирином. А новички ещё не заметили никаких повторяющихся закономерностей; или повторение их ещё не беспокоит. Головной боли просто нет.
Худшее, что вы можете сделать, — это заставить людей, которые не чувствуют боли, принимать аспирин. Точно так же попытка «обучить монадам» начинающих функциональных программистов, которые ещё не понимают необходимости в монадах, скорее всего, принесёт больше вреда, чем пользы, создавая дополнительную ненужную путаницу и увековечивая миф о том, что монады по своей сути сложны для понимания.
Итого
Строгая очерёдность проблем и решений является одним из определяющих фактором для эффективного понимания. Хорошо продуманный материал сразу же предлагает читателю поиграть с первоначальным расположением элементов и тем самым самостоятельно обнаружить потенциальные проблемы. Непосредственный опыт решения проблемы вызывает интеллектуальную потребность (или, если хотите, «головную боль») и создаёт основу для последующего внедрения решения. Поэтому лучшие обучающие материалы начинают с постановки проблемы, а не предлагают решение сразу. Но даже если это не так, изучая новую концепцию, придумайте (или погуглите), какую проблему она призвана решить. Это очень поможет пониманию и запоминанию.
Источник: https://mkremins.github.io/blog/doors-headaches-intellectual-need/
👍28
День 1726. #ЗаметкиНаПолях
Изменяем Имена Встроенных Ресурсов в .NET
Когда вы используете встроенные ресурсы (embedded resources) в проекте .NET, имя ресурса вычисляется на основе пути к файлу. По умолчанию используется формат, вроде <Имя сборки>.<Путь к файлу>. Но путь к файлу не содержит разделителя пути (/ или \). Вместо этого разделитель пути заменяется точкой. Например, для файла resources/index.html:
Можно изменить имена встроенных ресурсов, используя LogicalName:
Источник: https://www.meziantou.net/customizing-the-embedded-resource-name-in-dotnet.htm
Изменяем Имена Встроенных Ресурсов в .NET
Когда вы используете встроенные ресурсы (embedded resources) в проекте .NET, имя ресурса вычисляется на основе пути к файлу. По умолчанию используется формат, вроде <Имя сборки>.<Путь к файлу>. Но путь к файлу не содержит разделителя пути (/ или \). Вместо этого разделитель пути заменяется точкой. Например, для файла resources/index.html:
<Project>имя ресурса будет
<ItemGroup>
<EmbeddedResource Include="resources\index.html" />
</ItemGroup>
</project>
MyProject.resources.index.htmlВы можете вывести список встроенных ресурсов, используя метод GetManifestResourceNames класса Assembly.
foreach(var name inПример вывода:
Assembly.GetExecutingAssembly()
.GetManifestResourceNames())
{
Console.WriteLine(name);
}
MyProject.resources.favicon.icoОднако вы не можете быть на 100% уверены, как читать встроенные ресурсы, поскольку такое именование может вызывать конфликты.
MyProject.resources.img.background.png
MyProject.resources.index.html
Можно изменить имена встроенных ресурсов, используя LogicalName:
<Project>Если добавить это в проект и снова выполнить код выше, получится что-то вроде этого:
<ItemGroup>
<EmbeddedResource Include="Resources/**/*">
<LogicalName>
$([System.String]::new('%(RelativeDir)').Replace('\','/'))%(FileName)%(Extension)
</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Project>
Resources/favicon.icoИспользуя такое сопоставление, гораздо проще создать виртуальную файловую систему из встроенных ресурсов, поскольку имена файлов соответствуют фактической файловой иерархии.
Resources/img/background.png
Resources/index.html
Источник: https://www.meziantou.net/customizing-the-embedded-resource-name-in-dotnet.htm
👍13
День 1727. #Testing
Тестирование на Основе Свойств. Теория
В этой серии рассмотрим, что такое тестирование на основе свойств, почему оно полезно и как оно может помочь писать лучший код.
Примечание: это сложно! Оно рекомендуется для критических частей вашей кодовой базы, но вряд ли стоит его использовать везде.
Тестирование на основе свойств было введено в 2000 году Коэном Классеном и Джоном Хьюзом через библиотеку Haskell QuickCheck. Марк Симанн использует следующее определение в своем курсе Pluralsight по тестированию на основе свойств:
Тестирование на основе свойств — это метод автоматического тестирования, при котором вы постепенно концентрируетесь на правильном поведении системы, описывая её свойства или качества в общих чертах, а затем используете случайно сгенерированные тестовые данные для выполнения детерминированных тестов.
Оно довольно запутанное. Давайте разбираться.
Большинство тестов, которые пишут разработчики, — это тесты на основе примеров. Мы пытаемся подумать о том, какие входные данные будут репрезентативными для функций, которые мы хотим протестировать, и используем эти примеры для создания модульных тестов. Лучшие разработчики думают не только о счастливом пути, но и пытаются понять, что может быть неправильным вводом, чтобы увидеть, корректно ли функции обрабатывают условия сбоя.
Проблема в том, что, когда ваши функции достигают определённого уровня сложности, становится довольно трудно продумывать все возможные варианты (примеры). И хотя тестовое покрытие может составлять 100%, вы всё равно не на 100% уверены, что тесты охватывают все крайние случаи.
Тестирование на основе свойств может помочь справиться с недостатками тестов на основе примеров. Вместо того, чтобы находить подходящие примеры, мы пытаемся понять и представить взаимосвязь между нашими входными и выходными данными. Мы ищем правила, спецификации, «свойства», которые позволяют нам описать эту связь в общем виде, не уточняя, каким именно должен быть вход или выход.
Например:
1) Не имеет значения, в каком порядке мы вводим входные данные x и y, выходные данные одинаковы. 1+7 = 7+1
2) Ноль вместо x или y равносилен пустой операции (вывод не меняется). 7+0 = 0+7 = 7.
3) Если вызывать Add несколько раз, порядок вызовов не имеет значения. 7+(4+5) = (7+4)+5
Это прекрасно согласуется с математическим описанием операции сложения.
Пока это всё теория. Завтра рассмотрим тесты на основе свойств в C#.
Продолжение следует…
Источник: https://bartwullems.blogspot.com/2023/01/property-based-testing-in-cpart-1.html
Тестирование на Основе Свойств. Теория
В этой серии рассмотрим, что такое тестирование на основе свойств, почему оно полезно и как оно может помочь писать лучший код.
Примечание: это сложно! Оно рекомендуется для критических частей вашей кодовой базы, но вряд ли стоит его использовать везде.
Тестирование на основе свойств было введено в 2000 году Коэном Классеном и Джоном Хьюзом через библиотеку Haskell QuickCheck. Марк Симанн использует следующее определение в своем курсе Pluralsight по тестированию на основе свойств:
Тестирование на основе свойств — это метод автоматического тестирования, при котором вы постепенно концентрируетесь на правильном поведении системы, описывая её свойства или качества в общих чертах, а затем используете случайно сгенерированные тестовые данные для выполнения детерминированных тестов.
Оно довольно запутанное. Давайте разбираться.
Большинство тестов, которые пишут разработчики, — это тесты на основе примеров. Мы пытаемся подумать о том, какие входные данные будут репрезентативными для функций, которые мы хотим протестировать, и используем эти примеры для создания модульных тестов. Лучшие разработчики думают не только о счастливом пути, но и пытаются понять, что может быть неправильным вводом, чтобы увидеть, корректно ли функции обрабатывают условия сбоя.
Проблема в том, что, когда ваши функции достигают определённого уровня сложности, становится довольно трудно продумывать все возможные варианты (примеры). И хотя тестовое покрытие может составлять 100%, вы всё равно не на 100% уверены, что тесты охватывают все крайние случаи.
Тестирование на основе свойств может помочь справиться с недостатками тестов на основе примеров. Вместо того, чтобы находить подходящие примеры, мы пытаемся понять и представить взаимосвязь между нашими входными и выходными данными. Мы ищем правила, спецификации, «свойства», которые позволяют нам описать эту связь в общем виде, не уточняя, каким именно должен быть вход или выход.
Например:
int Add(int x, int y) => x+y;Чтобы протестировать метод Add, мы можем попытаться придумать репрезентативные примеры, но существует бесконечный список возможных комбинаций. Вместо этого попробуем описать метод Add как связь между входными и выходными данными:
1) Не имеет значения, в каком порядке мы вводим входные данные x и y, выходные данные одинаковы. 1+7 = 7+1
2) Ноль вместо x или y равносилен пустой операции (вывод не меняется). 7+0 = 0+7 = 7.
3) Если вызывать Add несколько раз, порядок вызовов не имеет значения. 7+(4+5) = (7+4)+5
Это прекрасно согласуется с математическим описанием операции сложения.
Пока это всё теория. Завтра рассмотрим тесты на основе свойств в C#.
Продолжение следует…
Источник: https://bartwullems.blogspot.com/2023/01/property-based-testing-in-cpart-1.html
👍14
День 1728. #Testing
Тестирование на Основе Свойств. Простой пример
Теория
Итак, напишем тесты согласно свойствам, которые мы определили.
FsCheck — это платформа тестирования на основе свойств, созданная для F#, но её можно использовать и в C#. Программист предоставляет спецификацию программы в виде свойств, которым должны удовлетворять функции, методы или объекты, а FsCheck проверяет, сохраняются ли эти свойства на большом количестве случайно сгенерированных случаев. Вы фактически пишете тестируемую спецификацию вашей программы. Спецификации выражаются на F#, C# или VB с использованием комбинаторов, определённых в библиотеке FsCheck. FsCheck предоставляет комбинаторы для определения свойств, наблюдения за распределением тестовых данных и определения генераторов тестовых данных. При сбое свойства FsCheck автоматически отображает минимальный контрпример.
Есть плагины FsCheck для всех популярных тестовых сред. Всё, что нам нужно, - это установить NuGet пакет и заменить атрибуты
Тесты по-прежнему будут проходить. По умолчанию FsCheck останавливается после 100 попыток. Если вы хотите знать протестированные значения, задайте свойству Verbose атрибута Property значение true:
Продолжение следует…
Источник: https://bartwullems.blogspot.com/2023/01/property-based-testing-in-cpart-2.html
Тестирование на Основе Свойств. Простой пример
Теория
Итак, напишем тесты согласно свойствам, которые мы определили.
int Add(int x, int y) => x+y;У нас должно получиться 3 теста:
public class AddTwoNumbersTestsПока это не сильно отличается от обычных тестов на основе примеров. Теперь задача состоит в том, чтобы сгенерировать правильные псевдослучайные значения, которые можно использовать в качестве входных данных. В этом нам поможет FsCheck.
{
int Add(int x, int y) => x + y;
[Theory]
public void NoOrderOfParameters(int x, int y)
{
var res1 = Add(x, y);
var res2 = Add(y, x);
Assert.Equal(res1, res2);
}
[Theory]
public void ZeroDoesNothing(int x)
{
var res1 = Add(x, 0);
var res2 = x;
Assert.Equal(res1, res2);
}
[Theory]
public void OrderDoesntMatter(int x, int y, int z)
{
var res1 = Add(Add(x, y), z);
var res2 = Add(x, Add(y, z));
Assert.Equal(res1, res2);
}
}
FsCheck — это платформа тестирования на основе свойств, созданная для F#, но её можно использовать и в C#. Программист предоставляет спецификацию программы в виде свойств, которым должны удовлетворять функции, методы или объекты, а FsCheck проверяет, сохраняются ли эти свойства на большом количестве случайно сгенерированных случаев. Вы фактически пишете тестируемую спецификацию вашей программы. Спецификации выражаются на F#, C# или VB с использованием комбинаторов, определённых в библиотеке FsCheck. FsCheck предоставляет комбинаторы для определения свойств, наблюдения за распределением тестовых данных и определения генераторов тестовых данных. При сбое свойства FsCheck автоматически отображает минимальный контрпример.
Есть плагины FsCheck для всех популярных тестовых сред. Всё, что нам нужно, - это установить NuGet пакет и заменить атрибуты
[Theory]
на [Property]
.Тесты по-прежнему будут проходить. По умолчанию FsCheck останавливается после 100 попыток. Если вы хотите знать протестированные значения, задайте свойству Verbose атрибута Property значение true:
[Property(Verbose = true)]Вот пример вывода:
NoOrderOfParametersКонечно, это очень простой пример. Далее рассмотрим что-то более реалистичное.
Standard Output:
0:
(0, 0)
1:
(-1, 1)
2:
(1, 1)
…
Продолжение следует…
Источник: https://bartwullems.blogspot.com/2023/01/property-based-testing-in-cpart-2.html
👍13
День 1729. #Testing
Тестирование на Основе Свойств. Реальный пример
Теория
Простой пример
Сегодня рассмотрим более реалистичный пример и функции, которые предоставляет FsCkeck. Допустим, нам нужно проверить номер кредитной карты.
Если у нас есть метод
Используем FsCheck:
Произвольные значения (Arbitraties)
FsCheck использует комбинацию генераторов (generator) и сокращателей (shrinker) для создания тестовых данных. Генераторы производят случайный набор значений из интервала с равномерным распределением. Сокращатели ограничивают (фильтруют) этот набор по заданному условию. В FsCheck определены произвольные значения по умолчанию для некоторых часто используемых типов:
- NegativeInt
- NonNegativeInt
- NonEmptyString
- IntWithMinMax
- NonEmptyArray
и т.п.
Используем альтернативную форму записи тестового метода с использованием предопределённых произвольных значений:
Продолжение следует…
Источник: https://bartwullems.blogspot.com/2023/01/property-based-testing-in-cpart-3.html
Тестирование на Основе Свойств. Реальный пример
Теория
Простой пример
Сегодня рассмотрим более реалистичный пример и функции, которые предоставляет FsCkeck. Допустим, нам нужно проверить номер кредитной карты.
Если у нас есть метод
CardNumber.IsValid()
, проверяющий валидность номера кредитной карты, мы можем добавить тесты, вроде следующих:[TestCase("12345678910")]Как видите, это вполне типичные примеры тестов. Некоторые магические значения использовались для проверки теста, но уверены ли мы, что охватили все крайние случаи?
[TestCase("12345621748")]
[TestCase("12345621777")]
[TestCase("Test")]
[TestCase("00000000000")]
[TestCase("99999999999")]
[TestCase("!@#!@%^@^@$^&@$^sdfasdf")]
[TestCase("$^@#^@##$44")]
[TestCase("15435#$%4354dfsg")]
[TestCase("90022742192")]
public void ValidationShouldFail(string num)
{
var result = CardNumber.IsValid(num);
result.Should().BeFalse();
}
Используем FsCheck:
[Property]Также можно использовать альтернативную форму записи теста:
public bool ValidationShouldFail(string num)
{
return !CardNumber.IsValid(num);
}
[Property]Тест проходит, но если посмотреть расшифровку (
public void ValidationShouldFail()
{
Prop.ForAll<string>(
x => !CardNumber.IsValid(x)
)
.VerboseCheck();
}
[Property(Verbose = true)]
), мы можем заметить, что проверяются случайные строки, и вряд ли хотя бы одна из них будет валидным номером карты. Мы можем заменить строку на long, но это тоже вряд ли сильно ограничит варианты.Произвольные значения (Arbitraties)
FsCheck использует комбинацию генераторов (generator) и сокращателей (shrinker) для создания тестовых данных. Генераторы производят случайный набор значений из интервала с равномерным распределением. Сокращатели ограничивают (фильтруют) этот набор по заданному условию. В FsCheck определены произвольные значения по умолчанию для некоторых часто используемых типов:
- NegativeInt
- NonNegativeInt
- NonEmptyString
- IntWithMinMax
- NonEmptyArray
и т.п.
Используем альтернативную форму записи тестового метода с использованием предопределённых произвольных значений:
[Property(Verbose = true)]Здесь мы использовали произвольные значения для long и функцию-сокращатель (x > 100). Заметьте, что FsCheck сначала генерирует случайные значения, а затем проверяет их на соответствие условию сокращателя. В примере выше при попытке задать большое значение в функции Filter, тесты могут выполняться очень долго.
public Property ValidationShouldFail()
{
var arb = Arb
.Default
.Int64()
.Filter(x => x > 100);
return Prop.ForAll<Int64>(
arb,
x => !CardNumber.IsValid(x.ToString()));
}
Продолжение следует…
Источник: https://bartwullems.blogspot.com/2023/01/property-based-testing-in-cpart-3.html
👍4
День 1730. #Testing
Тестирование на Основе Свойств. Собственный генератор
Теория
Простой пример
Реальный пример
Сегодня рассмотрим, как писать собственные генераторы.
В предыдущем примере мы использовали Filter(), чтобы возвращать только нужные числа.
Для создания генератора нужен публичный статический класс с публичным статическим методом, возвращающим Arbitrary<T>.
Например, так можно создать генератор месяца в определённом году:
В этом же классе можно создать свой сокращатель:
Источник: https://bartwullems.blogspot.com/2023/01/property-based-testing-in-cpart-4.html
Тестирование на Основе Свойств. Собственный генератор
Теория
Простой пример
Реальный пример
Сегодня рассмотрим, как писать собственные генераторы.
В предыдущем примере мы использовали Filter(), чтобы возвращать только нужные числа.
Для создания генератора нужен публичный статический класс с публичным статическим методом, возвращающим Arbitrary<T>.
public static class CCNumberGeneratorТеперь его можно использовать в качестве типа генератора в атрибуте Property:
{
public static Arbitrary<Int64> Generate()
{
return Arb.Default
.Int64()
.Filter(x => x > 100);
}
}
[Property(Arbitrary = new[] {В примере выше мы использовали существующий генератор. Но можно и создать его с нуля. Одной из наиболее часто используемых функций является
typeof(CCNumberGenerator) },
Verbose = true)]
public bool ValidateShouldFail(long num)
{
return !CardNumber.IsValid(num.ToString());
}
Gen.Choose()
, которая осуществляет случайный выбор значения из интервала с равномерным распределением.Например, так можно создать генератор месяца в определённом году:
public static class MonthOfYearGeneratorНа самом деле, вспомогательных функций для генератора очень много, и можно создавать генераторы любой сложности.
{
public static Gen<MonthOfYear> Generator =
from month in Gen.Choose(1, 12)
from year in Gen.Choose(1982, 2023)
select new MonthOfYear()
{
Month = month,
Year = year
};
public static Arbitrary<MonthOfYear> Generate() =>
Arb.From(Generator);
}
В этом же классе можно создать свой сокращатель:
public static IEnumerable<MonthOfYear>А затем использовать перегрузку метода Generate, принимающую и генератор, и сокращатель:
Shrinker(MonthOfYear moy)
{
yield return new MonthOfYear() {
Month = moy.Month,
Year = moy.Year - 1
};
yield return new MonthOfYear() {
Month = moy.Month,
Year = moy.Year + 1
};
}
public static Arbitrary<MonthOfYear> Generate() =>Окончание следует…
Arb.From(Generator, Shrinker);
Источник: https://bartwullems.blogspot.com/2023/01/property-based-testing-in-cpart-4.html
👍5
День 1731. #Testing
Тестирование на Основе Свойств. Воспроизведение
Теория
Простой пример
Реальный пример
Собственный генератор
Для каждого тестируемого свойства FsCheck генерирует случайные входные значения. Эти значения могут быть разными для каждого запуска теста, что означает, что каждый запуск может закончиться разными результатами. Поэтому, если у вас было неправильное входное значение, которое не прошло тест в предыдущий раз, вполне возможно, что при следующем запуске теста вы больше не увидите этот неправильный вход. Для простых входных значений это не должно быть проблемой. Но если вы используете более сложные входные данные, повторить неудачный тест может быть трудно.
Если посмотреть на выходные данные неудавшегося теста, можно заметить строку вроде
Ещё одна область, где могут пригодиться тесты на основе свойств, — это случаи, когда вам нужен своего рода приёмочный тест для какого-то кода. Например, у вас есть некоторый метод, в правильности которого вы уверены, но необходимо провести его рефакторинг, либо он недостаточно быстр. Вы можете написать тест на основе свойств, в котором свойство, которое должно соблюдаться, заключается в том, что для любых входных данных результат изначального метода должен совпадать с результатом нового. Затем увеличьте количество случайных входных данных настолько, чтобы можно было быть уверенным в правильности. И если тесты проходят, значит новый метод работает правильно.
Итого
Тесты на основе свойств полезны, но не являются панацеей. Их может быть сложнее читать другим разработчикам, которые не привыкли проводить тестирование на основе свойств. Когда вы решаете реализовать свои собственные произвольные алгоритмы и ограничиваете возможные произвольные значения, вы рискуете упустить важные случаи из-за излишней строгости, как и при написании обычных тестов. Тесты на основе свойств также выполняются медленнее: по умолчанию они генерируют 100 случайных входных данных и проверяют их. Поскольку вы имеете дело со случайностью, это также означает, что два прогона теста не идентичны. У вас может быть удачный, а затем неудачный прогон. Если второй запуск выявит реальную проблему, то всё в порядке. Следует написать специальный модульный тест для этого случая, а затем исправить проблему. Однако если это связано с тем, что один из ваших генераторов случайно генерирует значения, которые сильно отличаются от ожидаемых входных данных, выявить и устранить проблему может быть сложнее. Это связано с тем, что сначала вам нужно идентифицировать генератор, дающий неожиданные значения, и обернуть его механизмом фильтрации. И, хотя это возможно сделать, это всё же больше работы, чем простое изменение постоянного значения, определённого в модульном тесте.
Тестирование на основе свойств – очень мощный инструмент, о котором часто забывают. Оно действительно может выявить скрытые и неочевидные ошибки в самых сложных участках кода.
Источники:
- https://bartwullems.blogspot.com/2023/01/property-based-testing-in-cpart-5.html
- https://rasmus-feldthaus.medium.com/supercharge-your-testing-with-property-based-tests-bc3a7b75ca9f
Тестирование на Основе Свойств. Воспроизведение
Теория
Простой пример
Реальный пример
Собственный генератор
Для каждого тестируемого свойства FsCheck генерирует случайные входные значения. Эти значения могут быть разными для каждого запуска теста, что означает, что каждый запуск может закончиться разными результатами. Поэтому, если у вас было неправильное входное значение, которое не прошло тест в предыдущий раз, вполне возможно, что при следующем запуске теста вы больше не увидите этот неправильный вход. Для простых входных значений это не должно быть проблемой. Но если вы используете более сложные входные данные, повторить неудачный тест может быть трудно.
Если посмотреть на выходные данные неудавшегося теста, можно заметить строку вроде
Falsifiable, after 3 tests (4241 shrinks) (StdGen(318823861,297138967)).StdGen – это начальные значения, которые FsCheck использовал для генерации входных данных. Если вы хотите использовать в своём тесте точно такие же входные данные, используйте это значение в свойстве Replay атрибута Property:
[Property(Replay="318823861,297138967")]Приёмочные тесты на основе свойств
public bool ValidationShouldFail(long num)
{
…
}
Ещё одна область, где могут пригодиться тесты на основе свойств, — это случаи, когда вам нужен своего рода приёмочный тест для какого-то кода. Например, у вас есть некоторый метод, в правильности которого вы уверены, но необходимо провести его рефакторинг, либо он недостаточно быстр. Вы можете написать тест на основе свойств, в котором свойство, которое должно соблюдаться, заключается в том, что для любых входных данных результат изначального метода должен совпадать с результатом нового. Затем увеличьте количество случайных входных данных настолько, чтобы можно было быть уверенным в правильности. И если тесты проходят, значит новый метод работает правильно.
Итого
Тесты на основе свойств полезны, но не являются панацеей. Их может быть сложнее читать другим разработчикам, которые не привыкли проводить тестирование на основе свойств. Когда вы решаете реализовать свои собственные произвольные алгоритмы и ограничиваете возможные произвольные значения, вы рискуете упустить важные случаи из-за излишней строгости, как и при написании обычных тестов. Тесты на основе свойств также выполняются медленнее: по умолчанию они генерируют 100 случайных входных данных и проверяют их. Поскольку вы имеете дело со случайностью, это также означает, что два прогона теста не идентичны. У вас может быть удачный, а затем неудачный прогон. Если второй запуск выявит реальную проблему, то всё в порядке. Следует написать специальный модульный тест для этого случая, а затем исправить проблему. Однако если это связано с тем, что один из ваших генераторов случайно генерирует значения, которые сильно отличаются от ожидаемых входных данных, выявить и устранить проблему может быть сложнее. Это связано с тем, что сначала вам нужно идентифицировать генератор, дающий неожиданные значения, и обернуть его механизмом фильтрации. И, хотя это возможно сделать, это всё же больше работы, чем простое изменение постоянного значения, определённого в модульном тесте.
Тестирование на основе свойств – очень мощный инструмент, о котором часто забывают. Оно действительно может выявить скрытые и неочевидные ошибки в самых сложных участках кода.
Источники:
- https://bartwullems.blogspot.com/2023/01/property-based-testing-in-cpart-5.html
- https://rasmus-feldthaus.medium.com/supercharge-your-testing-with-property-based-tests-bc3a7b75ca9f
👍4
День 1732. #ЗаметкиНаПолях
Оптимизация памяти с помощью ArrayPool в C#
В C# пул массивов представлен классом ArrayPool<T>. Это потокобезопасный класс, предоставляющий структурированный механизм для эффективного управления и повторного использования массивов типа T.
Также можно использовать метод расширения Create():
Использование:
Здесь следует отметить, что фактический размер массива, который мы получаем из ArrayPool, как минимум равен размеру, который мы запрашиваем. Т.е. полученный массив может иметь большую длину. ArrayPool состоит из массивов с размерами, равными степени 2, начиная с длины 16. Таким образом, когда мы запрашиваем массив определённого размера, мы получаем ближайший доступный массив как минимум этого размера. В примере выше размер массива будет 16, а не 10.
Использование ArrayPool не только значительно быстрее, но и эффективно использует память. ArrayPool не выделяет память (кроме изначальной инициализации). Поэтому при интенсивном переиспользовании массивов разница между pool.Rent() и new становится огромной.
Итого
ArrayPool — отличный выбор, когда нужно оптимизировать память и уменьшить её фрагментацию, особенно в сценариях, где производительность критична. Он позволяет повторно использовать существующие блоки памяти посредством переиспользования массива. Однако придётся явно возвращать взятые массивы в пул с помощью метода Return(). Кроме того, арендованный массив может иметь размер, превышающий тот, который нам действительно нужен, что потребует специальных манипуляций для соответствия нашему конкретному сценарию использования. В приложениях, где производительность критична, и где часто используются и инициализируются массивы, предпочтительным вариантом является ArrayPool, тогда как для более простых случаев использования с менее частым созданием массивов предпочтительнее будет new.
Источник: https://code-maze.com/csharp-arraypool-memory-optimization/
Оптимизация памяти с помощью ArrayPool в C#
В C# пул массивов представлен классом ArrayPool<T>. Это потокобезопасный класс, предоставляющий структурированный механизм для эффективного управления и повторного использования массивов типа T.
var arrPool = ArrayPool<int>.Shared;Здесь мы создаём пул целочисленных массивов, который используется во всём приложении. Он имеет максимальную длину массива по умолчанию, равную 2^20 (1024*1024 = 1.048.576) байт.
Также можно использовать метод расширения Create():
var arrPool = ArrayPool<int>.Create(100, 10);Здесь первый аргумент метода Create() устанавливает максимальную длину массива в ArrayPool. Второй аргумент определяет количество массивов в сегменте. Пул группирует массивы одинаковой длины в эти сегменты, чтобы мы могли быстрее получить к ним доступ. Однако ограничивать пулы массивов этими параметрами нужно с осторожностью. Если мы превысим лимиты, произойдёт выделение памяти для нового массива.
Использование:
var pool = ArrayPool<int>.Shared;Сначала мы инициализируем пул, затем используем метод Rent() для получения массива длиной size из пула.
var size = 10;
var arr = pool.Rent(size);
for (var i = 0; i < size; i++)
arr[i] = i * 2;
Console.WriteLine("Элементы:");
for (var i = 0; i < size; i++)
Console.Write(arr[i] + " ");
pool.Return(arr);
// ВыводВ конце мы должны использовать метод Return(), чтобы отправить массив обратно в пул. Таким образом, он снова доступен для следующего использования.
Элементы:
0 2 4 6 8 10 12 14 16 18
Здесь следует отметить, что фактический размер массива, который мы получаем из ArrayPool, как минимум равен размеру, который мы запрашиваем. Т.е. полученный массив может иметь большую длину. ArrayPool состоит из массивов с размерами, равными степени 2, начиная с длины 16. Таким образом, когда мы запрашиваем массив определённого размера, мы получаем ближайший доступный массив как минимум этого размера. В примере выше размер массива будет 16, а не 10.
Использование ArrayPool не только значительно быстрее, но и эффективно использует память. ArrayPool не выделяет память (кроме изначальной инициализации). Поэтому при интенсивном переиспользовании массивов разница между pool.Rent() и new становится огромной.
Итого
ArrayPool — отличный выбор, когда нужно оптимизировать память и уменьшить её фрагментацию, особенно в сценариях, где производительность критична. Он позволяет повторно использовать существующие блоки памяти посредством переиспользования массива. Однако придётся явно возвращать взятые массивы в пул с помощью метода Return(). Кроме того, арендованный массив может иметь размер, превышающий тот, который нам действительно нужен, что потребует специальных манипуляций для соответствия нашему конкретному сценарию использования. В приложениях, где производительность критична, и где часто используются и инициализируются массивы, предпочтительным вариантом является ArrayPool, тогда как для более простых случаев использования с менее частым созданием массивов предпочтительнее будет new.
Источник: https://code-maze.com/csharp-arraypool-memory-optimization/
👍20
День 1733. #BestPractices #ProjectManagement
Принципы Бережливой Разработки ПО
Бережливая Разработка ПО (Lean Software Development) — это гибкая система управления проектами и разработки продуктов, основанная на принципах бережливого производства. Основное внимание уделяется обеспечению ценности для клиента путём оптимизации ресурсов, рабочих потоков и процессов. Ниже рассмотрим основные принципы бережливой разработки.
1. Устранение потерь
Эта концепция заимствована из мира бережливого производства, где она известна как «муда» (от японского бесполезность, расточительность). В разработке ПО потерями может быть что угодно: от написания ненужного кода до чрезмерных совещаний, которые не приносят никакой пользы. Цель состоит в том, чтобы оптимизировать рабочий процесс, выявляя и удаляя всё, что не помогает конечному продукту или не удовлетворяет потребностям клиента.
2. Усиленное обучение
Обучение является неотъемлемой частью разработки. Принцип усиленного обучения подчёркивает, что команда всегда должна находиться в состоянии непрерывного обучения. Будь то проверка кода, обратная связь или изучение новых материалов, этот принцип предполагает, что более информированная команда производит продукт более высокого качества. Такие практики, как предметно-ориентированное проектирование (DDD), помогают команде сосредоточиться на изучении и правильном моделировании предметной области.
3. Принятие решения как можно позже
Слишком раннее принятие решений может привести к переработке, если эти решения окажутся неправильными. Этот принцип советует отложить принятие решения до последнего ответственного момента. Это позволит команде получить максимальное количество информации и контекста перед принятием решения, тем самым снижая вероятность дорогостоящих ошибок.
4. Максимально быстрая поставка
Скорость и эффективность являются ключевыми факторами в бережливой разработке программного обеспечения. Этот принцип направлен на максимально быструю поставку функционального продукта покупателю. Речь идет не о спешке, а о поиске оптимального потока, который позволит выполнить быструю поставку без ущерба для качества. Важными показателями, которые команды могут отслеживать, чтобы определить скорость поставки готовых продуктов, являются
- время цикла (cycle time) - время, которое нужно команде, чтобы создать продукт,
- время поставки (lead time) – время между выставлением заказа клиентом и исполнением заказа.
5. Расширение возможностей команды
В рамках бережливой разработки ПО мотивированная и самостоятельная команда считается более эффективной и гибкой. Расширение прав и возможностей команды предполагает предоставление им автономии в принятии решений и ответственности за выполнение своих задач. Это создаёт чувство ответственности среди членов команды, повышая их производительность и продуктивность.
6. Обеспечение целостности
Качество не должно быть второстепенным вопросом; оно должно быть интегрировано в продукт с самого начала. Обеспечение целостности означает создание надёжной, удобной в обслуживании и адаптируемой системы с самого начала. Это требует стремления к совершенству от каждого члена команды на каждом этапе процесса разработки.
7. Оптимизация всего
Принципы бережливого производства подчеркивают важность рассмотрения процесса разработки как единого целого. Вместо того, чтобы сосредотачиваться исключительно на отдельных задачах или модулях, важно понять, как каждый элемент вписывается в общую картину. Оптимизируя всю систему, а не её части, вы можете обеспечить максимальную эффективность всего процесса.
Помните: «система, порождающая дефекты, является дефектной системой» - Джеффри Палермо. Обеспечьте качество всего процесса и выявляйте проблемы до того, как они покинут процесс.
Источник: https://ardalis.com/principles-lean-software-development/
Принципы Бережливой Разработки ПО
Бережливая Разработка ПО (Lean Software Development) — это гибкая система управления проектами и разработки продуктов, основанная на принципах бережливого производства. Основное внимание уделяется обеспечению ценности для клиента путём оптимизации ресурсов, рабочих потоков и процессов. Ниже рассмотрим основные принципы бережливой разработки.
1. Устранение потерь
Эта концепция заимствована из мира бережливого производства, где она известна как «муда» (от японского бесполезность, расточительность). В разработке ПО потерями может быть что угодно: от написания ненужного кода до чрезмерных совещаний, которые не приносят никакой пользы. Цель состоит в том, чтобы оптимизировать рабочий процесс, выявляя и удаляя всё, что не помогает конечному продукту или не удовлетворяет потребностям клиента.
2. Усиленное обучение
Обучение является неотъемлемой частью разработки. Принцип усиленного обучения подчёркивает, что команда всегда должна находиться в состоянии непрерывного обучения. Будь то проверка кода, обратная связь или изучение новых материалов, этот принцип предполагает, что более информированная команда производит продукт более высокого качества. Такие практики, как предметно-ориентированное проектирование (DDD), помогают команде сосредоточиться на изучении и правильном моделировании предметной области.
3. Принятие решения как можно позже
Слишком раннее принятие решений может привести к переработке, если эти решения окажутся неправильными. Этот принцип советует отложить принятие решения до последнего ответственного момента. Это позволит команде получить максимальное количество информации и контекста перед принятием решения, тем самым снижая вероятность дорогостоящих ошибок.
4. Максимально быстрая поставка
Скорость и эффективность являются ключевыми факторами в бережливой разработке программного обеспечения. Этот принцип направлен на максимально быструю поставку функционального продукта покупателю. Речь идет не о спешке, а о поиске оптимального потока, который позволит выполнить быструю поставку без ущерба для качества. Важными показателями, которые команды могут отслеживать, чтобы определить скорость поставки готовых продуктов, являются
- время цикла (cycle time) - время, которое нужно команде, чтобы создать продукт,
- время поставки (lead time) – время между выставлением заказа клиентом и исполнением заказа.
5. Расширение возможностей команды
В рамках бережливой разработки ПО мотивированная и самостоятельная команда считается более эффективной и гибкой. Расширение прав и возможностей команды предполагает предоставление им автономии в принятии решений и ответственности за выполнение своих задач. Это создаёт чувство ответственности среди членов команды, повышая их производительность и продуктивность.
6. Обеспечение целостности
Качество не должно быть второстепенным вопросом; оно должно быть интегрировано в продукт с самого начала. Обеспечение целостности означает создание надёжной, удобной в обслуживании и адаптируемой системы с самого начала. Это требует стремления к совершенству от каждого члена команды на каждом этапе процесса разработки.
7. Оптимизация всего
Принципы бережливого производства подчеркивают важность рассмотрения процесса разработки как единого целого. Вместо того, чтобы сосредотачиваться исключительно на отдельных задачах или модулях, важно понять, как каждый элемент вписывается в общую картину. Оптимизируя всю систему, а не её части, вы можете обеспечить максимальную эффективность всего процесса.
Помните: «система, порождающая дефекты, является дефектной системой» - Джеффри Палермо. Обеспечьте качество всего процесса и выявляйте проблемы до того, как они покинут процесс.
Источник: https://ardalis.com/principles-lean-software-development/
👍11
День 1734. #ЗаметкиНаПолях
Фоновые Задачи и Как Их Использовать. Начало
В .NET фоновые задачи — это асинхронные операции, которые выполняются независимо от основного потока приложения. Они используются для выполнения задач, которые не должны блокировать основной поток, например длительных вычислений, операций ввода-вывода или задач, которые могут выполняться одновременно.
Одной из распространённых реализаций является использование async/await:
Варианты использования в реальных приложениях
1. Уведомления по email:
Отправка уведомлений по email может занимать много времени и вызывать задержки в сети. Вы не хотите, чтобы основной поток приложения ждал завершения доставки email.
2. Обработка изображений и файлов:
Такие задачи, как изменение размера изображения, загрузка файлов или перекодирование видео, могут требовать больших ресурсов и времени.
3. Очистка и обслуживание базы данных:
В приложениях с БД рутинные задачи обслуживания, такие как архивирование, очистка старых данных или переиндексация, могут быть критически важными, но отнимать много времени. Такие задачи можно реализовать в фоновом процессе и запланировать на время минимальной нагрузки основного приложения.
4. Обслуживание кэша:
Со временем в кэшах могут накапливаться устаревшие данные, что приводит к неэффективности и увеличению использования памяти.
Завтра рассмотрим пример, как реализовать фоновую задачу очистки кэша.
Окончание следует…
Источник: https://stefandjokic.tech/posts/background-tasks-how-to-use-them
Фоновые Задачи и Как Их Использовать. Начало
В .NET фоновые задачи — это асинхронные операции, которые выполняются независимо от основного потока приложения. Они используются для выполнения задач, которые не должны блокировать основной поток, например длительных вычислений, операций ввода-вывода или задач, которые могут выполняться одновременно.
Одной из распространённых реализаций является использование async/await:
Console.WriteLine("Основной поток: старт");
var bgTask = Task.Run(() => DoBgWork());
// продолжаем работу в основном потоке
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"Основной поток: {i}...");
await Task.Delay(1000);
}
// ждём завершения фоновой задачи
await bgTask;
Console.WriteLine("Основной поток: завершено.");
static void DoBgWork()
{
Console.WriteLine("Фоновый поток: старт");
// какая-то длительная работа
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"Фоновый поток: {i}...");
Task.Delay(1000).Wait();
}
Console.WriteLine("Фоновый поток: завершено.");
}
Варианты использования в реальных приложениях
1. Уведомления по email:
Отправка уведомлений по email может занимать много времени и вызывать задержки в сети. Вы не хотите, чтобы основной поток приложения ждал завершения доставки email.
2. Обработка изображений и файлов:
Такие задачи, как изменение размера изображения, загрузка файлов или перекодирование видео, могут требовать больших ресурсов и времени.
3. Очистка и обслуживание базы данных:
В приложениях с БД рутинные задачи обслуживания, такие как архивирование, очистка старых данных или переиндексация, могут быть критически важными, но отнимать много времени. Такие задачи можно реализовать в фоновом процессе и запланировать на время минимальной нагрузки основного приложения.
4. Обслуживание кэша:
Со временем в кэшах могут накапливаться устаревшие данные, что приводит к неэффективности и увеличению использования памяти.
Завтра рассмотрим пример, как реализовать фоновую задачу очистки кэша.
Окончание следует…
Источник: https://stefandjokic.tech/posts/background-tasks-how-to-use-them
👍23
День 1735. #ЗаметкиНаПолях
Фоновые Задачи и Как Их Использовать. Окончание
Начало
Очистка кэша с помощью фоновой задачи
Вы можете создать фоновую задачу, которая запускается через регулярные промежутки времени, например раз в час или раз в день, чтобы проверять срок действия кэшированных элементов. Каждый кэшированный элемент может иметь метку времени или значение времени жизни (TTL), связанное с ним, чтобы указать, когда его следует считать устаревшим.
Вот как будет выглядеть упрощённое управление кэшем в приложении:
В этом примере CacheManager управляет кэшем и имеет фоновую задачу (StartCleanup), которая периодически удаляет устаревшие элементы в зависимости от их меток TTL. Это гарантирует, что кэш будет оставаться актуальным и не будет расти бесконечно:
Вывод:
Итого
Фоновые задачи – полезный инструмент для приложений .NET.
- Фоновые задачи предотвращают блокировку основного потока приложения длительными операциями, сохраняя отзывчивость UI и предотвращая зависание приложения.
- Выполняя ресурсоемкие задачи в фоновом режиме, приложения могут более эффективно использовать системные ресурсы, что приводит к повышению производительности и масштабируемости.
- Фоновые задачи обеспечивают параллельное выполнение задач, позволяя приложениям одновременно обрабатывать несколько операций, что важно для обработки больших рабочих нагрузок.
- Они идеально подходят для автоматизации рутинных задач, таких как очистка кэша, синхронизация данных и обслуживание баз данных, сокращая количество ручного вмешательства и обеспечивая точность данных.
- Фоновые задачи помогают эффективно управлять ресурсоёмкими операциями, такими как обработка изображений или доставка электронной почты, предотвращая истощение ресурсов.
- Они способствуют масштабируемости приложения, позволяя ему справляться с возросшей нагрузкой и требованиями без значительного снижения производительности.
Источник: https://stefandjokic.tech/posts/background-tasks-how-to-use-them
Фоновые Задачи и Как Их Использовать. Окончание
Начало
Очистка кэша с помощью фоновой задачи
Вы можете создать фоновую задачу, которая запускается через регулярные промежутки времени, например раз в час или раз в день, чтобы проверять срок действия кэшированных элементов. Каждый кэшированный элемент может иметь метку времени или значение времени жизни (TTL), связанное с ним, чтобы указать, когда его следует считать устаревшим.
Вот как будет выглядеть упрощённое управление кэшем в приложении:
var cache = new CacheManager();
// Добавляем элементы в кэш
cache.AddItem("item1", "value1",
TimeSpan.FromSeconds(30));
cache.AddItem("item2", "value2",
TimeSpan.FromMinutes(1));
// Начинаем очистку кэша
_ = Task.Run(() => cache.StartCleanup(
TimeSpan.FromSeconds(15)));
// Продолжаем работу приложения
Console.WriteLine("Приложение работает...");
Console.ReadLine();
В этом примере CacheManager управляет кэшем и имеет фоновую задачу (StartCleanup), которая периодически удаляет устаревшие элементы в зависимости от их меток TTL. Это гарантирует, что кэш будет оставаться актуальным и не будет расти бесконечно:
class CacheManager
{
private Dictionary<string, CacheItem>
cache = new();
public void AddItem(
string key,
object value,
TimeSpan expiration)
{
var item = new CacheItem(
value,
DateTime.Now.Add(expiration));
cache[key] = item;
}
public async Task StartCleanup(
TimeSpan interval)
{
while (true)
{
await Task.Delay(interval);
var now = DateTime.Now;
var toRemove = new List<string>();
foreach (var kvp in cache)
{
if (kvp.Value.Expiration < now)
toRemove.Add(kvp.Key);
}
foreach (var key in toRemove)
{
Console.WriteLine($"{key} удалён");
cache.Remove(key);
}
}
}
}
class CacheItem
{
public object Value { get; }
public DateTime Expiration { get; }
public CacheItem(object value,
DateTime expiration)
{
Value = value;
Expiration = expiration;
}
}
Вывод:
Приложение работает…Фоновые задачи по очистке кэша помогают поддерживать производительность приложений, обеспечивая эффективность кэша и избегая использования устаревших данных.
// через 30 секунд
item1 удалён
// через 1 минуту
item2 удалён
Итого
Фоновые задачи – полезный инструмент для приложений .NET.
- Фоновые задачи предотвращают блокировку основного потока приложения длительными операциями, сохраняя отзывчивость UI и предотвращая зависание приложения.
- Выполняя ресурсоемкие задачи в фоновом режиме, приложения могут более эффективно использовать системные ресурсы, что приводит к повышению производительности и масштабируемости.
- Фоновые задачи обеспечивают параллельное выполнение задач, позволяя приложениям одновременно обрабатывать несколько операций, что важно для обработки больших рабочих нагрузок.
- Они идеально подходят для автоматизации рутинных задач, таких как очистка кэша, синхронизация данных и обслуживание баз данных, сокращая количество ручного вмешательства и обеспечивая точность данных.
- Фоновые задачи помогают эффективно управлять ресурсоёмкими операциями, такими как обработка изображений или доставка электронной почты, предотвращая истощение ресурсов.
- Они способствуют масштабируемости приложения, позволяя ему справляться с возросшей нагрузкой и требованиями без значительного снижения производительности.
Источник: https://stefandjokic.tech/posts/background-tasks-how-to-use-them
👍7
День 1736. #ЧтоНовенького #Курсы
Microsoft Applied Skills
Applied Skills — новая, заверенная Microsoft, грамота, подтверждающая наличие у вас целевых навыков, необходимых для реализации важных проектов, соответствующих целям и задачам бизнеса. Программа Applied Skills даёт вам возможность продемонстрировать, на что вы способны и что вы можете привнести в ключевые проекты организации.
«Организации ищут таланты, которые смогут возглавить их проекты в области облачных вычислений», — отмечает Ким Акерс, корпоративный вице-президент по поддержке и эксплуатации решений для клиентов и партнёров Microsoft. - «Microsoft Applied Skills предлагает упрощённый способ проверки навыков кандидата. Когда вы видите навыки, заверенные Microsoft, вы знаете, что можете доверить этому человеку выполнение поставленной задачи».
На данный момент бесплатно в течение ограниченного времени предлагаются следующие грамоты (пока процесс только на английском языке):
- Secure storage for Azure Files and Azure Blob Storage
- Configure secure access to your workloads using Azure networking
- Deploy and configure Azure Monitor
- Deploy containers by using Azure Kubernetes Service
- Develop an ASP.NET Core web app that consumes an API
- Secure Azure services and workloads with Microsoft Defender for Cloud regulatory compliance controls
- Configure SIEM security operations using Microsoft Sentinel
- Create and manage automated processes by using Power Automate
Как получить грамоту Microsoft Applied Skills
1. Подготовьтесь самостоятельно, например, используя бесплатные курсы на Microsoft Learn.
2. Получите грамоту, пройдя онлайн интерактивную лабораторную работу, которая проведёт вас через ряд задач на основе сценариев в таких продуктах, как Microsoft Azure или Microsoft Power Platform. Лабораторную оценку можно получить непосредственно на Microsoft Learn.
3. Поделитесь своими новыми навыками. Вы получите грамоту, заверенную Microsoft, которую можно опубликовать в своём профиле.
Сертификат, грамота или то и другое?
Более 30 лет сертификаты служат доказательством технического мастерства мирового класса. В сегодняшней постоянно меняющейся бизнес-среде бывают случаи, когда необходимы подтверждённые навыки работы с конкретным проектом, предлагаемые грамотами Applied Skills. Вот ключевые отличия:
1. Цель
- Сертификат: проверяет общие технические знания
- Грамота: проверяет один конкретный навык
2. Контекст
- Сертификат: для определённой роли в компании
- Грамота: для определённого проекта
3. Охват
- Сертификат: широта навыков
- Грамота: специализированные для конкретного сценария навыки
4. Формат оценки
- Сертификат: экзамен с интерактивными элементами
- Грамота: лабораторная работа
5. Гибкость сдачи
- Сертификат: назначенное время
- Грамота: любое желаемое время
Источник: https://techcommunity.microsoft.com/t5/microsoft-learn-blog/announcing-microsoft-applied-skills-the-new-credentials-to/ba-p/3775645
Microsoft Applied Skills
Applied Skills — новая, заверенная Microsoft, грамота, подтверждающая наличие у вас целевых навыков, необходимых для реализации важных проектов, соответствующих целям и задачам бизнеса. Программа Applied Skills даёт вам возможность продемонстрировать, на что вы способны и что вы можете привнести в ключевые проекты организации.
«Организации ищут таланты, которые смогут возглавить их проекты в области облачных вычислений», — отмечает Ким Акерс, корпоративный вице-президент по поддержке и эксплуатации решений для клиентов и партнёров Microsoft. - «Microsoft Applied Skills предлагает упрощённый способ проверки навыков кандидата. Когда вы видите навыки, заверенные Microsoft, вы знаете, что можете доверить этому человеку выполнение поставленной задачи».
На данный момент бесплатно в течение ограниченного времени предлагаются следующие грамоты (пока процесс только на английском языке):
- Secure storage for Azure Files and Azure Blob Storage
- Configure secure access to your workloads using Azure networking
- Deploy and configure Azure Monitor
- Deploy containers by using Azure Kubernetes Service
- Develop an ASP.NET Core web app that consumes an API
- Secure Azure services and workloads with Microsoft Defender for Cloud regulatory compliance controls
- Configure SIEM security operations using Microsoft Sentinel
- Create and manage automated processes by using Power Automate
Как получить грамоту Microsoft Applied Skills
1. Подготовьтесь самостоятельно, например, используя бесплатные курсы на Microsoft Learn.
2. Получите грамоту, пройдя онлайн интерактивную лабораторную работу, которая проведёт вас через ряд задач на основе сценариев в таких продуктах, как Microsoft Azure или Microsoft Power Platform. Лабораторную оценку можно получить непосредственно на Microsoft Learn.
3. Поделитесь своими новыми навыками. Вы получите грамоту, заверенную Microsoft, которую можно опубликовать в своём профиле.
Сертификат, грамота или то и другое?
Более 30 лет сертификаты служат доказательством технического мастерства мирового класса. В сегодняшней постоянно меняющейся бизнес-среде бывают случаи, когда необходимы подтверждённые навыки работы с конкретным проектом, предлагаемые грамотами Applied Skills. Вот ключевые отличия:
1. Цель
- Сертификат: проверяет общие технические знания
- Грамота: проверяет один конкретный навык
2. Контекст
- Сертификат: для определённой роли в компании
- Грамота: для определённого проекта
3. Охват
- Сертификат: широта навыков
- Грамота: специализированные для конкретного сценария навыки
4. Формат оценки
- Сертификат: экзамен с интерактивными элементами
- Грамота: лабораторная работа
5. Гибкость сдачи
- Сертификат: назначенное время
- Грамота: любое желаемое время
Источник: https://techcommunity.microsoft.com/t5/microsoft-learn-blog/announcing-microsoft-applied-skills-the-new-credentials-to/ba-p/3775645
👍7👎1
День 1737. #ЗаметкиНаПолях #Git
Организация Нескольких Идентичностей в Git
Короткий совет, как управлять несколькими идентичностями в Git. Например, личными проектами, рабочими, и раздельно для каждого клиента.
Я организую свои репозитории Git в три уровня. Мои личные проекты находятся в каталоге
Уровень 2 — это клиент, например,
Уровень 3 — это репозиторий проекта, например,
Вот как организован рабочий каталог:
Теперь предположим, что client2 требует, чтобы мы делали коммиты с идентичностью, отличной от нашей рабочей электронной почты по умолчанию. Кроме того, у вас, вероятно, также есть личный адрес электронной почты для ваших проектов.
Одна из замечательных особенностей файла .gitconfig заключается в том, что вы можете условно включать в него другие файлы конфигурации, и в этом вся суть:
По умолчанию мое имя и адрес электронной почты всегда соответствуют моей личной информации. Я также храню здесь некоторые другие глобальные настройки, но они нам сейчас не важны. Если репозиторий расположен внутри каталога
Надеюсь, идея понятна. Для каждой идентичности вы сохраняете отдельный файл gitconfig и включаете его в основной файл
Этот трюк немного упростил адаптацию моего проекта. Больше никаких запросов от клиентов «Вы забыли обновить свой email»!
Источник: https://garrit.xyz/posts/2023-10-13-organizing-multiple-git-identities
Автор оригинала: Garrit Franke
Организация Нескольких Идентичностей в Git
Короткий совет, как управлять несколькими идентичностями в Git. Например, личными проектами, рабочими, и раздельно для каждого клиента.
Я организую свои репозитории Git в три уровня. Мои личные проекты находятся в каталоге
~/sources
. Все рабочие проекты находятся в ~/work
. Это первый уровень.Уровень 2 — это клиент, например,
~/work/client1
. Уровень 3 — это репозиторий проекта, например,
~/work/client1/foo-api
.Вот как организован рабочий каталог:
/Users/garrit/work
├── client1
│ ├── foo-api
│ ├── foo-ios
│ └── foo-android
└── client2
├── bar-ios
└── bar-middleware
Теперь предположим, что client2 требует, чтобы мы делали коммиты с идентичностью, отличной от нашей рабочей электронной почты по умолчанию. Кроме того, у вас, вероятно, также есть личный адрес электронной почты для ваших проектов.
.gitconfig
– это глобальный файл конфигурации Git, расположенный в корневом каталоге. Если вы когда-либо задавали такой параметр, как git config user.name «Foo Bar»: именно здесь он и сохранялся.Одна из замечательных особенностей файла .gitconfig заключается в том, что вы можете условно включать в него другие файлы конфигурации, и в этом вся суть:
[user]
name = Garrit Franke
email = [email protected]
[includeIf "gitdir:~/work/"]
path = ~/.gitconfig-work
[includeIf "gitdir:~/work/client2/"]
path = ~/.gitconfig-client2
[includeIf "gitdir:~/sources/"]
path = ~/.gitconfig-personal
# ...
По умолчанию мое имя и адрес электронной почты всегда соответствуют моей личной информации. Я также храню здесь некоторые другие глобальные настройки, но они нам сейчас не важны. Если репозиторий расположен внутри каталога
~/work
, в него включается файл с именем ~/.gitconfig-work
. Это просто ещё один файл gitconfig. Вот как он выглядит в моём случае:[user]
name = Garrit Franke
signingkey = 12345678
email = [email protected]
[commit]
gpgsign = true
Надеюсь, идея понятна. Для каждой идентичности вы сохраняете отдельный файл gitconfig и включаете его в основной файл
~/.gitconfig
. Важно отметить, что для этого вам необходимо организовать ваши репозитории, сгруппировав их по клиентам.Этот трюк немного упростил адаптацию моего проекта. Больше никаких запросов от клиентов «Вы забыли обновить свой email»!
Источник: https://garrit.xyz/posts/2023-10-13-organizing-multiple-git-identities
Автор оригинала: Garrit Franke
👍27
День 1738. #ЗаметкиНаПолях #Debugging
Правила Отладки: Хватит Думать, Наблюдайте
Очень важно наблюдать за неудачей. Когда вы делаете предположения о причине проблемы, вы часто в итоге пытаетесь исправить что-то, не связанное с реальной ошибкой. Это не только приводит к неэффективному решению, но также отнимает драгоценное время и ресурсы.
Перестаньте слишком много думать и начните наблюдать. Наблюдение требует усилий. Часто это сложнее, чем нам хотелось бы. В ПО наблюдение подразумевает установку точек останова, вставку операторов отладки, мониторинг переменных и проверку состояния памяти.
После того как вы опровергли свои первоначальные предположения, задача идентификации ошибки никуда не делась, а время упущено. Вот несколько рекомендаций, которые помогут вам отдать предпочтение наблюдениям над преждевременными предположениями.
1. Посмотрите на сбой
Очевидно, что, чтобы идентифицировать сбой, необходимо посмотреть, как сбой произошёл. Отчёт об ошибке – это последствия сбоя. Для эффективной отладки необходимо изучить сбой в деталях. Иначе вы можете решить предполагаемую проблему, тогда как неисправность будет в другом месте. В большинстве случаев наблюдение занимает меньше времени, чем разбор поспешных догадок, которые часто приводят в тупик.
2. Посмотрите подробности
Обычно каждое следующее появление сбоя даёт вам дополнительные детали о природе ошибки. Продолжайте процесс наблюдения до тех пор, пока видимый сбой не сократится до управляемого числа потенциальных причин, требующих дальнейшего изучения.
3. Создайте инструментарий
Обычно по умолчанию можно запустить код в режиме отладки, что позволяет наблюдать за выполнением программы. Также помогает трассировка. Важно иметь механизм, который позволит выборочно включать или отключать определённые сообщения или типы сообщений. Это позволит сосредоточить внимание на сообщениях, имеющих отношение к конкретной проблеме. Учитывайте вопросы отладки с начала процесса проектирования. Убедитесь, что инструментарий трассировки и отладки являются одним из требований к вашему продукту.
4. Остерегайтесь Гейзенбагов
Гейзенберг - один из первопроходцев в квантовой физике. Он осознал, что само наблюдение за элементарными частицами влияет на их поведение. Гейзенбаг — это сбой, который реагирует на действие наблюдения. Например, исчезает в режиме отладки. Даже отладчик может влиять на поведение системы. Это неизбежная реальность, и очень важно помнить об этом, чтобы такие последствия не застали вас врасплох. Поэтому после внедрения инструментов отладки в неисправную систему важно воссоздать ошибку и убедиться, что ваши действия не повлияли на сбой.
5. Гадайте только, чтобы сузить поиск
Угадывание может быть ценным инструментом, но важно использовать догадки как средство сузить область поиска. Вы всё равно должны подтверждать свои предположения, воспроизводя сбой, прежде чем пытаться его исправить.
Когда вы сталкиваетесь с неожиданной ошибкой, важно пересмотреть ваши предположения. Чем больше вы уверены в коде, тем больше удивитесь ошибке в нём. Поэтому, столкнувшись с «поразительным» сбоем, важно признать, что одно или несколько ваших основополагающих предположений неверны. Если тщательное исследование не может подтвердить конкретное предположение, пришло время сделать шаг назад и пересмотреть свои догадки. Если ошибка возникла из-за неправильных представлений члена команды, важно коллективно обсудить проблему. Если один что-то неправильно понимает, возможно, и другие разделяют его заблуждение.
Вы также должны выяснить, почему эта проблема до сих пор оставалась незамеченной. Убедитесь, что что бы ни произошло, у вас есть механизмы для обнаружения этого сбоя, если он произойдёт снова.
Источник: https://dev.to/rajasegar/debugging-rules-quit-thinking-and-look-3ang
Правила Отладки: Хватит Думать, Наблюдайте
Очень важно наблюдать за неудачей. Когда вы делаете предположения о причине проблемы, вы часто в итоге пытаетесь исправить что-то, не связанное с реальной ошибкой. Это не только приводит к неэффективному решению, но также отнимает драгоценное время и ресурсы.
Перестаньте слишком много думать и начните наблюдать. Наблюдение требует усилий. Часто это сложнее, чем нам хотелось бы. В ПО наблюдение подразумевает установку точек останова, вставку операторов отладки, мониторинг переменных и проверку состояния памяти.
После того как вы опровергли свои первоначальные предположения, задача идентификации ошибки никуда не делась, а время упущено. Вот несколько рекомендаций, которые помогут вам отдать предпочтение наблюдениям над преждевременными предположениями.
1. Посмотрите на сбой
Очевидно, что, чтобы идентифицировать сбой, необходимо посмотреть, как сбой произошёл. Отчёт об ошибке – это последствия сбоя. Для эффективной отладки необходимо изучить сбой в деталях. Иначе вы можете решить предполагаемую проблему, тогда как неисправность будет в другом месте. В большинстве случаев наблюдение занимает меньше времени, чем разбор поспешных догадок, которые часто приводят в тупик.
2. Посмотрите подробности
Обычно каждое следующее появление сбоя даёт вам дополнительные детали о природе ошибки. Продолжайте процесс наблюдения до тех пор, пока видимый сбой не сократится до управляемого числа потенциальных причин, требующих дальнейшего изучения.
3. Создайте инструментарий
Обычно по умолчанию можно запустить код в режиме отладки, что позволяет наблюдать за выполнением программы. Также помогает трассировка. Важно иметь механизм, который позволит выборочно включать или отключать определённые сообщения или типы сообщений. Это позволит сосредоточить внимание на сообщениях, имеющих отношение к конкретной проблеме. Учитывайте вопросы отладки с начала процесса проектирования. Убедитесь, что инструментарий трассировки и отладки являются одним из требований к вашему продукту.
4. Остерегайтесь Гейзенбагов
Гейзенберг - один из первопроходцев в квантовой физике. Он осознал, что само наблюдение за элементарными частицами влияет на их поведение. Гейзенбаг — это сбой, который реагирует на действие наблюдения. Например, исчезает в режиме отладки. Даже отладчик может влиять на поведение системы. Это неизбежная реальность, и очень важно помнить об этом, чтобы такие последствия не застали вас врасплох. Поэтому после внедрения инструментов отладки в неисправную систему важно воссоздать ошибку и убедиться, что ваши действия не повлияли на сбой.
5. Гадайте только, чтобы сузить поиск
Угадывание может быть ценным инструментом, но важно использовать догадки как средство сузить область поиска. Вы всё равно должны подтверждать свои предположения, воспроизводя сбой, прежде чем пытаться его исправить.
Когда вы сталкиваетесь с неожиданной ошибкой, важно пересмотреть ваши предположения. Чем больше вы уверены в коде, тем больше удивитесь ошибке в нём. Поэтому, столкнувшись с «поразительным» сбоем, важно признать, что одно или несколько ваших основополагающих предположений неверны. Если тщательное исследование не может подтвердить конкретное предположение, пришло время сделать шаг назад и пересмотреть свои догадки. Если ошибка возникла из-за неправильных представлений члена команды, важно коллективно обсудить проблему. Если один что-то неправильно понимает, возможно, и другие разделяют его заблуждение.
Вы также должны выяснить, почему эта проблема до сих пор оставалась незамеченной. Убедитесь, что что бы ни произошло, у вас есть механизмы для обнаружения этого сбоя, если он произойдёт снова.
Источник: https://dev.to/rajasegar/debugging-rules-quit-thinking-and-look-3ang
👍5
День 1739. #BestPractices #ProjectManagement
Раздувание Процессов: Тихий Убийца Продуктивности Разработчиков
На начальных стадиях проекта разработки команды отличаются гибкостью, быстрым принятием решений и стремлением предоставлять ценные функции. Однако по мере того, как проекты усложняются и масштабируются, многие из них становятся жертвами коварного антипаттерна: раздувания процессов.
Факторов, приводящих к этому, множество:
1. Организационная культура.
Слишком осторожная организация может создать несколько уровней бюрократии, предполагая, что чем больше формализованы процессы тем меньше риск.
2. Недостаток доверия.
Руководство, которому не хватает уверенности в возможностях разработчиков, может навязать несколько уровней утверждения и документацию.
3. Сложность масштаба.
Расширение проектов часто влечёт увеличение числа заинтересованных сторон, каждая из которых добавляет свой уровень сложности и свои процессы.
4. Устаревший багаж.
Иногда ненужные процессы задерживаются просто потому, что «так было всегда».
Последствия
1. Снижение производительности.
Разработчики часто тратят больше времени на административную работу, чем на фактическую разработку.
2. Утечка инноваций.
Бюрократия может подавить творчество и ограничить эксперименты.
3. Задержка вывода продукта на рынок.
Сложные процессы удлиняют циклы разработки.
4. Снижение морального духа.
Потеря гибкости и рутина процессов могут подорвать моральный дух команды.
Примеры раздувания процессов
1. Чрезмерные проверки кода.
Обязательное проведение нескольких уровней проверок даже для тривиальных изменений может серьёзно замедлить цикл разработки.
2. Слишком сложные системы заявок.
Сложные системы тикетов, требующие заполнения множества полей ещё до того, как задача будет одобрена, могут занять столько же времени, сколько и исполнение задачи.
3. Обязательные отчеты.
Требование подробных отчетов с описанием каждой потраченной минуты может отнять время и отвлечь внимание от фактического кодирования.
4. Чрезмерное количество совещаний
Борьба с раздуванием процессов
1. Регулярные аудиты.
Последовательно анализируйте существующие процессы для оценки их актуальности и эффективности. Это следует делать в рамках регулярных командных (и организационных) ретроспектив. Но убедитесь, что такие аудиты полезны, а не усугубляют проблему раздувания процессов!
2. Принципы бережливости и гибкости.
Примите методологии, направленные на получение максимальной отдачи при минимальных затратах на процессы. Многие agile-практики, подчёркивают важность обеспечения быстрого прохождения процесса с минимальными церемониями.
3. Поощряйте доверие и автономию.
Дайте разработчикам полномочия принимать решения без ненужных бюрократических одобрений. Ваша команда не сможет заслужить ваше доверие, если вы как менеджер первый не доверитесь ей.
4. Минимально жизнеспособный процесс.
Внедряйте только те процессы, которые абсолютно необходимы для поддержания качества и контроля. Если сомневаетесь, выбросьте. Если есть возможность сократить процессы и повысить производительность, поэкспериментируйте с этим и посмотрите, сработает ли это для вашей команды и организации.
Итого
Раздувание процессов — это тихий, но смертоносный фактор, подрывающий продуктивность разработки ПО. Распознав его симптомы и приняв упреждающие меры, команды смогут вернуть себе гибкость и дух творчества, а проекты вернуть на путь эффективности и инноваций.
Источник: https://ardalis.com/process-bloat-silent-killer-developer-productivity/
Раздувание Процессов: Тихий Убийца Продуктивности Разработчиков
На начальных стадиях проекта разработки команды отличаются гибкостью, быстрым принятием решений и стремлением предоставлять ценные функции. Однако по мере того, как проекты усложняются и масштабируются, многие из них становятся жертвами коварного антипаттерна: раздувания процессов.
Факторов, приводящих к этому, множество:
1. Организационная культура.
Слишком осторожная организация может создать несколько уровней бюрократии, предполагая, что чем больше формализованы процессы тем меньше риск.
2. Недостаток доверия.
Руководство, которому не хватает уверенности в возможностях разработчиков, может навязать несколько уровней утверждения и документацию.
3. Сложность масштаба.
Расширение проектов часто влечёт увеличение числа заинтересованных сторон, каждая из которых добавляет свой уровень сложности и свои процессы.
4. Устаревший багаж.
Иногда ненужные процессы задерживаются просто потому, что «так было всегда».
Последствия
1. Снижение производительности.
Разработчики часто тратят больше времени на административную работу, чем на фактическую разработку.
2. Утечка инноваций.
Бюрократия может подавить творчество и ограничить эксперименты.
3. Задержка вывода продукта на рынок.
Сложные процессы удлиняют циклы разработки.
4. Снижение морального духа.
Потеря гибкости и рутина процессов могут подорвать моральный дух команды.
Примеры раздувания процессов
1. Чрезмерные проверки кода.
Обязательное проведение нескольких уровней проверок даже для тривиальных изменений может серьёзно замедлить цикл разработки.
2. Слишком сложные системы заявок.
Сложные системы тикетов, требующие заполнения множества полей ещё до того, как задача будет одобрена, могут занять столько же времени, сколько и исполнение задачи.
3. Обязательные отчеты.
Требование подробных отчетов с описанием каждой потраченной минуты может отнять время и отвлечь внимание от фактического кодирования.
4. Чрезмерное количество совещаний
Борьба с раздуванием процессов
1. Регулярные аудиты.
Последовательно анализируйте существующие процессы для оценки их актуальности и эффективности. Это следует делать в рамках регулярных командных (и организационных) ретроспектив. Но убедитесь, что такие аудиты полезны, а не усугубляют проблему раздувания процессов!
2. Принципы бережливости и гибкости.
Примите методологии, направленные на получение максимальной отдачи при минимальных затратах на процессы. Многие agile-практики, подчёркивают важность обеспечения быстрого прохождения процесса с минимальными церемониями.
3. Поощряйте доверие и автономию.
Дайте разработчикам полномочия принимать решения без ненужных бюрократических одобрений. Ваша команда не сможет заслужить ваше доверие, если вы как менеджер первый не доверитесь ей.
4. Минимально жизнеспособный процесс.
Внедряйте только те процессы, которые абсолютно необходимы для поддержания качества и контроля. Если сомневаетесь, выбросьте. Если есть возможность сократить процессы и повысить производительность, поэкспериментируйте с этим и посмотрите, сработает ли это для вашей команды и организации.
Итого
Раздувание процессов — это тихий, но смертоносный фактор, подрывающий продуктивность разработки ПО. Распознав его симптомы и приняв упреждающие меры, команды смогут вернуть себе гибкость и дух творчества, а проекты вернуть на путь эффективности и инноваций.
Источник: https://ardalis.com/process-bloat-silent-killer-developer-productivity/
👍7
День 1740. #Карьера
Чек-листы. Как Ничего не Забыть
Основная проблема разработки ПО в том, что происходит огромное количество процессов, а наш мозг не способен решать несколько задач одновременно.
Проблема не в том, что вы не знаете, как сделать, а в том, что вы забываете это сделать, хотя знаете, что должны. Простое решение - чек-листы.
Контрольный список поможет вам сосредоточиться на сложных частях вашей задачи, отвлекая внимание от разных мелочей. Однако он не должен ограничивать вас — он существует, чтобы помочь вам не забывать выполнять тривиальные, но важные действия.
Чек-листы бывают двух видов:
- Прочитал—сделал. Цель — читать каждый пункт и выполнять действия строго друг за другом.
- Сделал—отметил. Цель - выполнять действия, а затем проверять и подтверждать завершённые действия отметкой.
Например, чек-лист для новой кодовой базы:
1. Использовать Git.
2. Автоматизировать сборку.
3. Включить все сообщения об ошибках.
1. Использовать Git.
Первое, что нужно сделать в новой кодовой базе, — инициализировать локальный репозиторий Git. Рекомендация – делать это для любой кодовой базы, которая должна прожить больше недели. Вы всегда можете всё отменить, просто удалив папку .git.
2. Автоматизировать сборку.
Создайте минимальный объём кода, который сможете развернуть. Даже если у вас нет конвейера развёртывания или доступа к производственной среде. Создайте файл сценария, выполняющего сборку, и тоже отправьте коммит в Git. Например, простой .bat файл с командой:
Обратите внимание на сборку в режиме Release. Автоматизированная сборка должна отражать то, что в итоге будет запущено в производство. По мере добавления шагов сборки их следует добавлять и в скрипт.
3. Включить все сообщения об ошибках.
Старайтесь использовать предупреждения компилятора и другие автоматические инструменты — они способны находить разные проблемы с кодом. Быстро устранить сотню существующих предупреждений может быть сложно. Гораздо проще реагировать на предупреждение в момент его появления. Поэтому первое, что нужно сделать в новой кодовой базе, — включить параметр «Представлять предупреждения как ошибки». Это поможет избежать накопления любых предупреждений компилятора.
Кроме того, добавьте статические анализаторы кода, такие как Roslyn. Статический анализ кода похож на автоматизированный код-ревью. В отличие от предупреждений компилятора, статические анализаторы часто дают ложные срабатывания, но обычно предлагают разные варианты их подавления, так что не стоит их игнорировать.
Добавление проверок в существующую кодовую базу
Часто вы можете включить один тип предупреждений за раз. В существующей кодовой базе уже могут быть сотни предупреждений. Извлеките список и сгруппируйте его по типам. Выберите конкретный тип предупреждений, исправьте их, пока они ещё являются предупреждениями, чтобы можно было продолжать работу с кодом. А после превратите эти предупреждения в ошибки. Затем перейдите к другому типу предупреждений или другой части кодовой базы.
Ключевой момент — правило бойскаута: оставлять код в лучшем состоянии, чем вы его нашли.
Преимущество обработки предупреждений как ошибок в том, что вы переходите на новый уровень качества. При рассмотрении предупреждений как ошибок и включении статического анализа кода вы теряете часть контроля. Это звучит неприятно, но может стать вашим преимуществом.
Когда сверху от вас требуют «просто сделать побыстрее», т.к. «нет времени делать как положено», представьте, что вы отвечаете: «Если я сделаю так, код не скомпилируется». Даже если это будет не очень честно, вы всегда сможете утверждать, что конечная цель — это качественное ПО. Это должно быть выгодно для всей организации.
Источник: Марк Симан “Код, который умещается в голове”. СПб.: Питер, 2023. Глава 2.
Чек-листы. Как Ничего не Забыть
Основная проблема разработки ПО в том, что происходит огромное количество процессов, а наш мозг не способен решать несколько задач одновременно.
Проблема не в том, что вы не знаете, как сделать, а в том, что вы забываете это сделать, хотя знаете, что должны. Простое решение - чек-листы.
Контрольный список поможет вам сосредоточиться на сложных частях вашей задачи, отвлекая внимание от разных мелочей. Однако он не должен ограничивать вас — он существует, чтобы помочь вам не забывать выполнять тривиальные, но важные действия.
Чек-листы бывают двух видов:
- Прочитал—сделал. Цель — читать каждый пункт и выполнять действия строго друг за другом.
- Сделал—отметил. Цель - выполнять действия, а затем проверять и подтверждать завершённые действия отметкой.
Например, чек-лист для новой кодовой базы:
1. Использовать Git.
2. Автоматизировать сборку.
3. Включить все сообщения об ошибках.
1. Использовать Git.
Первое, что нужно сделать в новой кодовой базе, — инициализировать локальный репозиторий Git. Рекомендация – делать это для любой кодовой базы, которая должна прожить больше недели. Вы всегда можете всё отменить, просто удалив папку .git.
2. Автоматизировать сборку.
Создайте минимальный объём кода, который сможете развернуть. Даже если у вас нет конвейера развёртывания или доступа к производственной среде. Создайте файл сценария, выполняющего сборку, и тоже отправьте коммит в Git. Например, простой .bat файл с командой:
dotnet build --configuration Release
Обратите внимание на сборку в режиме Release. Автоматизированная сборка должна отражать то, что в итоге будет запущено в производство. По мере добавления шагов сборки их следует добавлять и в скрипт.
3. Включить все сообщения об ошибках.
Старайтесь использовать предупреждения компилятора и другие автоматические инструменты — они способны находить разные проблемы с кодом. Быстро устранить сотню существующих предупреждений может быть сложно. Гораздо проще реагировать на предупреждение в момент его появления. Поэтому первое, что нужно сделать в новой кодовой базе, — включить параметр «Представлять предупреждения как ошибки». Это поможет избежать накопления любых предупреждений компилятора.
Кроме того, добавьте статические анализаторы кода, такие как Roslyn. Статический анализ кода похож на автоматизированный код-ревью. В отличие от предупреждений компилятора, статические анализаторы часто дают ложные срабатывания, но обычно предлагают разные варианты их подавления, так что не стоит их игнорировать.
Добавление проверок в существующую кодовую базу
Часто вы можете включить один тип предупреждений за раз. В существующей кодовой базе уже могут быть сотни предупреждений. Извлеките список и сгруппируйте его по типам. Выберите конкретный тип предупреждений, исправьте их, пока они ещё являются предупреждениями, чтобы можно было продолжать работу с кодом. А после превратите эти предупреждения в ошибки. Затем перейдите к другому типу предупреждений или другой части кодовой базы.
Ключевой момент — правило бойскаута: оставлять код в лучшем состоянии, чем вы его нашли.
Преимущество обработки предупреждений как ошибок в том, что вы переходите на новый уровень качества. При рассмотрении предупреждений как ошибок и включении статического анализа кода вы теряете часть контроля. Это звучит неприятно, но может стать вашим преимуществом.
Когда сверху от вас требуют «просто сделать побыстрее», т.к. «нет времени делать как положено», представьте, что вы отвечаете: «Если я сделаю так, код не скомпилируется». Даже если это будет не очень честно, вы всегда сможете утверждать, что конечная цель — это качественное ПО. Это должно быть выгодно для всей организации.
Источник: Марк Симан “Код, который умещается в голове”. СПб.: Питер, 2023. Глава 2.
👍16
День 1741. #ЗаметкиНаПолях #Testing
Пишем Тесты с Autofixture
AutoFixture - мощный инструмент для юнит-тестирования повседневных задач. Он помогает писать меньше кода в блоке Arrange. Рассмотрим его использование на примере совместно с библиотекой xUnit.
Сначала надо создать AutoFixture в тестовом классе:
AutoFixture использует обобщённый метод Create, генерирующий случайные данные для заданного типа, например:
Однако, с помощью дополнительного пакета AutoFixture.Xunit2, вы можете автоматически создавать целые классы, вообще без блока Arrange с помощью атрибута AutoData:
Либо можно использовать метод Create:
Здесь все свойства классов будут заданы случайными значениями.
Вы можете управлять созданием, задавая данные для определённых свойств. Также можно создавать коллекции элементов:
Здесь вызов OmitAutoProperties не будет задавать случайные значения свойствам, у которых есть значения по умолчанию. А Without не будет задавать значение выбранного свойства (в примере выше City останется null).
Вы можете создавать реализации интерфейсов с помощью метода Register:
Здесь каждый раз, когда Autofixture нужно будет создать класс, зависящий от IMyInterface, будет создаваться экземпляр FakeMyInterface.
AutoFixture также можно использовать с пакетами для создания моков, вроде Moq или NSubstitute. Для этого надо настроить создание Autofixture (пример для Moq):
Тогда Autofixture можно будет использовать для создания реализаций интерфейсов:
При этом установка ConfigureMembers в true приводит к тому, что для классов-реализаций интерфейсов Autofixture сгенерирует случайные значения для свойств.
Здесь можно посмотреть множество других примеров использования AutoFixture.
Источник: https://dev.to/serhii_korol_ab7776c50dba/you-write-unit-tests-wrong-5d9f
Пишем Тесты с Autofixture
AutoFixture - мощный инструмент для юнит-тестирования повседневных задач. Он помогает писать меньше кода в блоке Arrange. Рассмотрим его использование на примере совместно с библиотекой xUnit.
Сначала надо создать AutoFixture в тестовом классе:
private readonly IFixture _fixture;
public SampleTests()
{
_fixture = new Fixture();
}
AutoFixture использует обобщённый метод Create, генерирующий случайные данные для заданного типа, например:
var name = _fixture.Create<string>();
var age = _fixture.Create<int>();
Однако, с помощью дополнительного пакета AutoFixture.Xunit2, вы можете автоматически создавать целые классы, вообще без блока Arrange с помощью атрибута AutoData:
[Theory, AutoData]
public void TestEmployee(
string name, int age,
string pos, decimal rate)
{
// Act
var emp = new Employee(name, age, pos, rate);
// Assert
emp.Name.Should().Be(name);
emp.Age.Should().Be(age);
emp.Position.Should().Be(pos);
emp.Rate.Should().Be(rate);
}
Либо можно использовать метод Create:
[Fact]
public void TestEmployee()
{
// Arrange
var emp = _fixture.Create<Employee>();
var comp = _fixture.Create<Company>();
…
}
Здесь все свойства классов будут заданы случайными значениями.
Вы можете управлять созданием, задавая данные для определённых свойств. Также можно создавать коллекции элементов:
var emps = _fixture
.CreateMany<Employee>(5).ToList();
var comp = _fixture.Build<Company>()
.OmitAutoProperties()
.With(x => x.Employees, emps)
.Without(x => x.City)
.Create();
Здесь вызов OmitAutoProperties не будет задавать случайные значения свойствам, у которых есть значения по умолчанию. А Without не будет задавать значение выбранного свойства (в примере выше City останется null).
Вы можете создавать реализации интерфейсов с помощью метода Register:
_fixture.Register<IMyInterface>(() =>
new FakeMyInterface());
Здесь каждый раз, когда Autofixture нужно будет создать класс, зависящий от IMyInterface, будет создаваться экземпляр FakeMyInterface.
AutoFixture также можно использовать с пакетами для создания моков, вроде Moq или NSubstitute. Для этого надо настроить создание Autofixture (пример для Moq):
var _fixture = new Fixture()
.Customize(new AutoMoqCustomization
{ ConfigureMembers = true });
Тогда Autofixture можно будет использовать для создания реализаций интерфейсов:
var result = _fixture.Create<IMyInterface>();
При этом установка ConfigureMembers в true приводит к тому, что для классов-реализаций интерфейсов Autofixture сгенерирует случайные значения для свойств.
Здесь можно посмотреть множество других примеров использования AutoFixture.
Источник: https://dev.to/serhii_korol_ab7776c50dba/you-write-unit-tests-wrong-5d9f
👍24
День 1742. #ЧтоНовенького
«Короткая» Маршрутизация в .NET 8
Маршрутизация в ASP.NET Core обрабатывается двумя частями промежуточного ПО:
- EndpointRoutingMiddleware (RoutingMiddleware) — выбирает, какую зарегистрированную конечную точку выполнить для данного запроса.
- EndpointMiddleware — обычно размещается в конце конвейера промежуточного ПО и выполняет выбранную конечную точку.
Это разделение помогает размещать промежуточное ПО между RoutingMiddleware и EndpointMiddleware, которое может изменять своё поведение на основе метаданных, связанных с конечной точкой, и выполняться до выполнения самой конечной точки. Например, так работают AuthorizationMiddleware и CorsMiddleware.
См. схему
Обычно именно так работает маршрутизация независимо от того, используете ли вы минимальные API или контроллеры MVC, и она легко расширяема. Вы можете добавить дополнительные метаданные к конечным точкам, а затем добавить дополнительное промежуточное ПО между RoutingMiddleware и EndpointMiddleware, чтобы обеспечить новое поведение. Но иногда конечной точке не требуется авторизация, поддержка CORS и т.п.
«Короткая» (short-circuit) маршрутизация — новая функция в .NET 8, которая означает, что конечная точка «пропускает» промежуточное ПО между RoutingMiddleware и EndpointMiddleware. Т.е. RoutingMiddleware немедленно выполняет конечную точку и отбрасывает остальную часть конвейера.
Например:
Здесь конечная точка "/" будет выполнена сразу в RoutingMiddleware. Также можно добавить код HTTP статуса:
Когда это полезно
Основной вариант использования — сократить накладные расходы на запросы, которые, как вы знаете, либо вернут ответ 404, либо никогда не потребуют авторизации или CORS. Некоторыми примерами могут быть известные URL-адреса, которые браузеры запрашивают автоматически, или другие стандартные пути. Например:
-
-
-
Это простые, хорошо известные URL-адреса, которые браузер и другие сайты могут запрашивать автоматически. Если вы не добавите их на свой сайт, то каждый запрос на них будет проходить через промежуточное ПО, только чтобы вернуть 404. Это большая лишняя работа. «Короткие» маршруты позволяют избежать этих накладных расходов.
Источник: https://andrewlock.net/exploring-the-dotnet-8-preview-short-circuit-routing/
«Короткая» Маршрутизация в .NET 8
Маршрутизация в ASP.NET Core обрабатывается двумя частями промежуточного ПО:
- EndpointRoutingMiddleware (RoutingMiddleware) — выбирает, какую зарегистрированную конечную точку выполнить для данного запроса.
- EndpointMiddleware — обычно размещается в конце конвейера промежуточного ПО и выполняет выбранную конечную точку.
Это разделение помогает размещать промежуточное ПО между RoutingMiddleware и EndpointMiddleware, которое может изменять своё поведение на основе метаданных, связанных с конечной точкой, и выполняться до выполнения самой конечной точки. Например, так работают AuthorizationMiddleware и CorsMiddleware.
См. схему
Обычно именно так работает маршрутизация независимо от того, используете ли вы минимальные API или контроллеры MVC, и она легко расширяема. Вы можете добавить дополнительные метаданные к конечным точкам, а затем добавить дополнительное промежуточное ПО между RoutingMiddleware и EndpointMiddleware, чтобы обеспечить новое поведение. Но иногда конечной точке не требуется авторизация, поддержка CORS и т.п.
«Короткая» (short-circuit) маршрутизация — новая функция в .NET 8, которая означает, что конечная точка «пропускает» промежуточное ПО между RoutingMiddleware и EndpointMiddleware. Т.е. RoutingMiddleware немедленно выполняет конечную точку и отбрасывает остальную часть конвейера.
Например:
app.MapGet("/", () => "Hello World!")
.ShortCircuit();
Здесь конечная точка "/" будет выполнена сразу в RoutingMiddleware. Также можно добавить код HTTP статуса:
….ShortCircuit(201);
Когда это полезно
Основной вариант использования — сократить накладные расходы на запросы, которые, как вы знаете, либо вернут ответ 404, либо никогда не потребуют авторизации или CORS. Некоторыми примерами могут быть известные URL-адреса, которые браузеры запрашивают автоматически, или другие стандартные пути. Например:
-
/robots.txt
— сообщает веб-роботам, таким как Google, что индексировать.-
/favicon.ico
— значок вкладки в браузере, который автоматически запрашивается браузером.-
/.well-known/*
(все пути имеют префикс .well-known/) — используется различными спецификациями, такими как OpenID Connect, security.txt или webfinger.Это простые, хорошо известные URL-адреса, которые браузер и другие сайты могут запрашивать автоматически. Если вы не добавите их на свой сайт, то каждый запрос на них будет проходить через промежуточное ПО, только чтобы вернуть 404. Это большая лишняя работа. «Короткие» маршруты позволяют избежать этих накладных расходов.
var builder = WebApplication
.CreateBuilder(args);
var app = builder.Build();
// возвращаем 404
app.MapGet("/favicon.ico",
() => Task.CompletedTask)
.ShortCircuit(404);
// возвращаем корректный robots.txt
app.MapGet("/robots.txt",
() => """
User-agent: *
Allow: /
""")
.ShortCircuit(200);
// любой запрос к /.well-known/ вернёт 404
app.MapShortCircuit(404, ".well-known");
// все другие запросы будут проходить
// через полный конвейер промежуточного ПО
app.MapGet("/", () => "Hello World!");
app.Run();
Источник: https://andrewlock.net/exploring-the-dotnet-8-preview-short-circuit-routing/
👍18
День 1743. #ВопросыНаСобеседовании #Многопоточность
Самые часто задаваемые вопросы на собеседовании по C#
26. Объясните концепцию ThreadLocal и секционирования данных, и как это может помочь улучшить общую производительность многопоточного приложения?
ThreadLocal
Локальное хранилище потока — это концепция, которая позволяет каждому потоку в многопоточном приложении иметь собственный экземпляр переменной. Локальная переменная потока сохраняет своё значение на протяжении всего времени существования потока и инициализируется один раз для каждого потока. Предоставляя каждому потоку свою копию переменной, мы можем минимизировать конфликты и повысить производительность, поскольку при доступе к переменной синхронизация не требуется.
В C# можно использовать класс ThreadLocal<T> для объявления локальной переменной потока:
Свойство IsValueCreated локальной переменной потока возвращает true, если переменная уже была инициализирована в этом потоке. Так можно определить, что управление вернулось в созданный ранее поток.
Секционирование данных
Это метод обработки данных, при котором большой набор данных делится на более мелкие независимые части. Затем каждая часть обрабатывается отдельным потоком параллельно. Секционирование данных позволяет лучше использовать системные ресурсы, уменьшает конфликты и помогает повысить общую производительность параллельных алгоритмов.
Перераспределение может выполняться статически или динамически, в зависимости от конкретной задачи и целей приложения. Parallel.ForEach и Parallel LINQ (PLINQ) — это два примера встроенных механизмов .NET, которые используют секционирование данных для более эффективного выполнения параллельных операций.
Пример разделения данных с использованием Parallel.ForEach:
Итого
Локальное хранилище потоков и секционирование данных — это два способа значительно повысить производительность и эффективность многопоточных приложений на C#. Они помогают минимизировать конфликты, уменьшить накладные расходы на блокировку и лучше использовать доступные системные ресурсы. Очень важно выбрать подходящий метод, исходя из характера проблемы и задействованных алгоритмов.
Источник: https://dev.to/bytehide/c-multithreading-interview-questions-and-answers-4opj
Самые часто задаваемые вопросы на собеседовании по C#
26. Объясните концепцию ThreadLocal и секционирования данных, и как это может помочь улучшить общую производительность многопоточного приложения?
ThreadLocal
Локальное хранилище потока — это концепция, которая позволяет каждому потоку в многопоточном приложении иметь собственный экземпляр переменной. Локальная переменная потока сохраняет своё значение на протяжении всего времени существования потока и инициализируется один раз для каждого потока. Предоставляя каждому потоку свою копию переменной, мы можем минимизировать конфликты и повысить производительность, поскольку при доступе к переменной синхронизация не требуется.
В C# можно использовать класс ThreadLocal<T> для объявления локальной переменной потока:
var localSum = new ThreadLocal<int>(() => 0);
// Каждый поток может безопасно использовать и изменять свою localSum без синхронизации
localSum.Value += 1;
Свойство IsValueCreated локальной переменной потока возвращает true, если переменная уже была инициализирована в этом потоке. Так можно определить, что управление вернулось в созданный ранее поток.
Секционирование данных
Это метод обработки данных, при котором большой набор данных делится на более мелкие независимые части. Затем каждая часть обрабатывается отдельным потоком параллельно. Секционирование данных позволяет лучше использовать системные ресурсы, уменьшает конфликты и помогает повысить общую производительность параллельных алгоритмов.
Перераспределение может выполняться статически или динамически, в зависимости от конкретной задачи и целей приложения. Parallel.ForEach и Parallel LINQ (PLINQ) — это два примера встроенных механизмов .NET, которые используют секционирование данных для более эффективного выполнения параллельных операций.
Пример разделения данных с использованием Parallel.ForEach:
var data = new List<int> { … };
Parallel.ForEach(data, item =>
{
// обработка элемента
});
Итого
Локальное хранилище потоков и секционирование данных — это два способа значительно повысить производительность и эффективность многопоточных приложений на C#. Они помогают минимизировать конфликты, уменьшить накладные расходы на блокировку и лучше использовать доступные системные ресурсы. Очень важно выбрать подходящий метод, исходя из характера проблемы и задействованных алгоритмов.
Источник: https://dev.to/bytehide/c-multithreading-interview-questions-and-answers-4opj
👍21