День 1701. #ЗаметкиНаПолях #Microservices
Оркестрация Или Хореография. Окончание
Начало
Хореография — коммуникация через события
Это децентрализованный подход к коммуникации. Хореография использует взаимодействие, управляемое событиями. Событие – это то, что произошло в прошлом и является фактом. Отправитель не знает, кто будет обрабатывать событие и что произойдёт после его обработки.
Преимущества:
- Слабая связанность
- Простота обслуживания
- Децентрализованное управление
- Асинхронная связь
Хореография позволяет микросервисам быть слабо связанными, что означает, что они могут работать независимо и асинхронно. Это делает систему более масштабируемой и отказоустойчивой. Сбой одного микросервиса не обязательно повлияет на остальные.
Недостатки:
- Сложность
- Усложнён мониторинг и устранение неполадок
- Сложнее реализовать и поддерживать, чем оркестрацию.
Когда использовать:
- Процесс может полагаться на входное сообщение без необходимости дополнительного контекста.
- Шаги чётко следуют друг за другом.
- Прогресс идёт в одном направлении.
Вы можете получить выгоду от повышенной гибкости (например, изолированное изменение отдельных шагов). К сожалению, хореография может затруднить отслеживание, отладку или мониторинг процессов, запускаемых событием. И чем больше поток событий, тем сложнее он становится.
Итого
Оркестрация определяет последовательность шагов, которым должен следовать каждый микросервис. Это отлично подходит для выявления и устранения сложных взаимозависимостей сервисов. Ещё одним преимуществом является то, что бизнес-логикой можно управлять и отслеживать её в одном месте.
С другой стороны, хореография — это децентрализованный метод взаимодействия микросервисов. Каждый сервис может работать независимо, оставаясь при этом частью более крупной архитектуры.
Чтобы решить, какой подход использовать, следует понаблюдать за системой и определить, что вы выиграете или потеряете. Хотя можно использовать гибридный подход, объединяющий оркестрацию и хореографию. При этом вы решаете, какой метод коммуникации использовать для конкретного рабочего процесса. Некоторые рабочие процессы могут выиграть от оркестровки, а другие — от хореографии.
Источник: https://www.milanjovanovic.tech/blog/solving-race-conditions-with-ef-core-optimistic-locking
Оркестрация Или Хореография. Окончание
Начало
Хореография — коммуникация через события
Это децентрализованный подход к коммуникации. Хореография использует взаимодействие, управляемое событиями. Событие – это то, что произошло в прошлом и является фактом. Отправитель не знает, кто будет обрабатывать событие и что произойдёт после его обработки.
Преимущества:
- Слабая связанность
- Простота обслуживания
- Децентрализованное управление
- Асинхронная связь
Хореография позволяет микросервисам быть слабо связанными, что означает, что они могут работать независимо и асинхронно. Это делает систему более масштабируемой и отказоустойчивой. Сбой одного микросервиса не обязательно повлияет на остальные.
Недостатки:
- Сложность
- Усложнён мониторинг и устранение неполадок
- Сложнее реализовать и поддерживать, чем оркестрацию.
Когда использовать:
- Процесс может полагаться на входное сообщение без необходимости дополнительного контекста.
- Шаги чётко следуют друг за другом.
- Прогресс идёт в одном направлении.
Вы можете получить выгоду от повышенной гибкости (например, изолированное изменение отдельных шагов). К сожалению, хореография может затруднить отслеживание, отладку или мониторинг процессов, запускаемых событием. И чем больше поток событий, тем сложнее он становится.
Итого
Оркестрация определяет последовательность шагов, которым должен следовать каждый микросервис. Это отлично подходит для выявления и устранения сложных взаимозависимостей сервисов. Ещё одним преимуществом является то, что бизнес-логикой можно управлять и отслеживать её в одном месте.
С другой стороны, хореография — это децентрализованный метод взаимодействия микросервисов. Каждый сервис может работать независимо, оставаясь при этом частью более крупной архитектуры.
Чтобы решить, какой подход использовать, следует понаблюдать за системой и определить, что вы выиграете или потеряете. Хотя можно использовать гибридный подход, объединяющий оркестрацию и хореографию. При этом вы решаете, какой метод коммуникации использовать для конкретного рабочего процесса. Некоторые рабочие процессы могут выиграть от оркестровки, а другие — от хореографии.
Источник: https://www.milanjovanovic.tech/blog/solving-race-conditions-with-ef-core-optimistic-locking
👍9
День 1702. #ВопросыНаСобеседовании #Многопоточность
Самые часто задаваемые вопросы на собеседовании по C#
23. Как обеспечить взаимоисключающий доступ к общим ресурсам в многопоточной системе в C# без использования lock или Monitor?
Вы можете использовать другие примитивы синхронизации. Некоторые распространенные альтернативы:
1) Мьютекс: гарантирует, что только один поток может одновременно получить доступ к общему ресурсу. В отличие от lock, мьютекс – примитив ОС и может обеспечивать межпроцессную синхронизацию. Пример:
UPD: спасибо подписчикам, напомнили про прекрасный доклад о примитивах синхронизации от Станислава Сидристого.
Источник: https://dev.to/bytehide/c-multithreading-interview-questions-and-answers-4opj
Самые часто задаваемые вопросы на собеседовании по C#
23. Как обеспечить взаимоисключающий доступ к общим ресурсам в многопоточной системе в C# без использования lock или Monitor?
Вы можете использовать другие примитивы синхронизации. Некоторые распространенные альтернативы:
1) Мьютекс: гарантирует, что только один поток может одновременно получить доступ к общему ресурсу. В отличие от lock, мьютекс – примитив ОС и может обеспечивать межпроцессную синхронизацию. Пример:
var mutex = new Mutex();2) Семафор: ограничивает количество одновременных потоков, которые могут получить доступ к общему ресурсу. Пример:
//...
mutex.WaitOne();
try
{
// Доступ к общему ресурсу
}
finally
{
mutex.ReleaseMutex();
}
var sem = new Semaphore(1, 1);3) ReaderWriterLockSlim: обеспечивает эффективный доступ для чтения и записи к общим ресурсам. Позволяет выполнять несколько одновременных операций чтения, когда ни один писатель не удерживает блокировку на запись. Пример:
// Начальное и максимальное количество
// потоков установлено в 1
//...
sem.WaitOne();
try
{
// Доступ к общему ресурсу
}
finally
{
sem.Release();
}
var rwLock = new ReaderWriterLockSlim();4) SpinLock: пытается получить блокировку до тех пор, пока не будет достигнут успех. SpinLock следует использовать в сценариях с низким уровнем конфликтов, когда ожидается, что блокировка будет удерживаться в течение очень короткого времени. Пример:
//...
// Чтение
rwLock.EnterReadLock();
try
{
// Доступ к общему ресурсу
}
finally
{
rwLock.ExitReadLock();
}
//...
// Запись
rwLock.EnterWriteLock();
try
{
// Доступ к общему ресурсу
}
finally
{
rwLock.ExitWriteLock();
}
var spinLock = new SpinLock();Помните, что эти примитивы синхронизации имеют более высокие накладные расходы чем обычный lock.
bool lockTaken = false;
//...
spinLock.Enter(ref lockTaken);
try
{
// Доступ к общему ресурсу
}
finally
{
if (lockTaken)
{
spinLock.Exit();
}
}
UPD: спасибо подписчикам, напомнили про прекрасный доклад о примитивах синхронизации от Станислава Сидристого.
Источник: https://dev.to/bytehide/c-multithreading-interview-questions-and-answers-4opj
👍17
День 1703. #МоиИнструменты
Тестируем Конечные Точки HTTP в Visual Studio 2022
В Visual Studio 17.6 представлен новый инструмент, Обозреватель Конечных Точек (Endpoints Explorer), который упрощает процесс обнаружения и тестирования конечных точек API.
Чтобы использовать его, перейдите в View > Other Windows > Endpoint Explorer (Вид > Другие окна > Обозреватель конечных точек).
Он автоматически определит конечные точки в проекте, предоставляя обзор проектов и связанных с ними конечных точек (см. в правой панели на рисунке). Если вызвать команду Generate Request (Создать запрос), будет создан HTTP-файл с запросом для конечной точки (слева на рисунке).
Ссылки над запросами позволяют отправить запрос к запущенному приложению или запустить отладку приложения (Debug). Результат показан в панели по центру на рисунке.
Этот инструмент значительно упрощает процесс тестирования конечных точек и проверки ответа, позволяя не переходить лишний раз в Postman.
Источник
Тестируем Конечные Точки HTTP в Visual Studio 2022
В Visual Studio 17.6 представлен новый инструмент, Обозреватель Конечных Точек (Endpoints Explorer), который упрощает процесс обнаружения и тестирования конечных точек API.
Чтобы использовать его, перейдите в View > Other Windows > Endpoint Explorer (Вид > Другие окна > Обозреватель конечных точек).
Он автоматически определит конечные точки в проекте, предоставляя обзор проектов и связанных с ними конечных точек (см. в правой панели на рисунке). Если вызвать команду Generate Request (Создать запрос), будет создан HTTP-файл с запросом для конечной точки (слева на рисунке).
Ссылки над запросами позволяют отправить запрос к запущенному приложению или запустить отладку приложения (Debug). Результат показан в панели по центру на рисунке.
Этот инструмент значительно упрощает процесс тестирования конечных точек и проверки ответа, позволяя не переходить лишний раз в Postman.
Источник
👍27👎1
День 1704. #ЗаметкиНаПолях
Использование SQL-Функций в Entity Framework
SQL Server (или другая база данных) имеет множество встроенных функций, которые можно использовать в запросах. Но в Entity Framework их нельзя использовать напрямую.
Некоторые функции имеют аналоги в .NET, например, для добавления дней к дате вы используете DATEADD в TSQL, а в C# это становится DateTime.AddDays. Но, например, SOUNDEX в TSQL (для поиска похожих строк вместо полного совпадения) не имеет C#-версии.
Вы можете написать свою реализацию на C# или просто зарегистрировать эти SQL-функции в DBContext. После регистрации функции вы можете использовать её в EF-запросах независимо от поставщика БД.
Зарегистрируем функцию SOUNDEX. Для этого создадим новый метод в DbContext и аннотируем его атрибутом DbFunction.
Теперь можно использовать метод SoundEx в запросах:
Чтобы убрать проверку на NULL, можно установить свойство IsNullable атрибута DbFunction в false:
Итого
В целом, использование DbFunctions может быть полезным способом воспользоваться преимуществами определённых функций базы данных в запросах EF. Но, поскольку вы используете функцию, специфичную для базы данных, становится сложнее переносить код на другие базы данных, если вы когда-нибудь захотите это сделать. В нашем примере функция
Источник: https://timdeschryver.dev/blog/consuming-sql-functions-with-entity-framework
Использование SQL-Функций в Entity Framework
SQL Server (или другая база данных) имеет множество встроенных функций, которые можно использовать в запросах. Но в Entity Framework их нельзя использовать напрямую.
Некоторые функции имеют аналоги в .NET, например, для добавления дней к дате вы используете DATEADD в TSQL, а в C# это становится DateTime.AddDays. Но, например, SOUNDEX в TSQL (для поиска похожих строк вместо полного совпадения) не имеет C#-версии.
Вы можете написать свою реализацию на C# или просто зарегистрировать эти SQL-функции в DBContext. После регистрации функции вы можете использовать её в EF-запросах независимо от поставщика БД.
Зарегистрируем функцию SOUNDEX. Для этого создадим новый метод в DbContext и аннотируем его атрибутом DbFunction.
public class MyDbContext : DbContextЗамечание: реализовывать метод не надо, только предоставить правильную сигнатуру.
{
…
[DbFunction(Name = "SoundEx",
IsBuiltIn = true)]
public static string SoundEx(string input)
{
throw new NotImplementedException();
}
}
Теперь можно использовать метод SoundEx в запросах:
app.MapGet("/customers",Когда запрос выполняется, генерируется следующий код SQL:
([FromQuery] name, MyDbContext ctx) => {
return ctx.Customers
.Where(c => MyDbContext.SoundEx(c.Name) ==
MyDbContext.SoundEx(customerName))
.ToListAsync();
});
SELECT [c].[Id], [c].[Name]Функция по запросу "Timothy", вернёт также слова, вроде "Timmothy", "Timoteo" или "Timotheo".
FROM [Customers] AS [c]
WHERE SoundEx([c].[Name]) = SoundEx(N'Timothy')
OR ((SoundEx([c].[Name]) IS NULL)
AND (SoundEx(N'Timothy') IS NULL))
Чтобы убрать проверку на NULL, можно установить свойство IsNullable атрибута DbFunction в false:
[DbFunction(Name = "SoundEx",Помимо встроенных функций, вы также можете создавать собственные и аналогичным образом добавлять их в DbContext. Для пользовательских функций установите для свойства IsBuiltIn значение false, а также определите схему функции:
IsBuiltIn = true,
IsNullable = false)]
public static string SoundEx(string input)
{
throw new NotImplementedException();
}
[DbFunction(Name = "MyCustomFunction",Злоупотреблять этим не рекомендуется, но регистрация существующих функций может быть полезна при переносе существующей базы кода в более новую версию.
Schema = "dbo",
IsBuiltIn = false)]
public static int MyCustomFunction(int input)
{
throw new NotImplementedException();
}
Итого
В целом, использование DbFunctions может быть полезным способом воспользоваться преимуществами определённых функций базы данных в запросах EF. Но, поскольку вы используете функцию, специфичную для базы данных, становится сложнее переносить код на другие базы данных, если вы когда-нибудь захотите это сделать. В нашем примере функция
SOUNDEX
существует не во всех базах данных или имеет другое имя. Если вы когда-нибудь захотите переключиться на другую базу данных, нужно будет пересмотреть все добавленные DbFunctions.Источник: https://timdeschryver.dev/blog/consuming-sql-functions-with-entity-framework
👍17
День 1706. #ЗаметкиНаПолях
Мультитаргетинг NuGet-Пакетов
При создании NuGet-пакета мы хотели бы использовать минимально возможную версию платформы (чтобы обеспечить максимальный охват), но также пользоваться преимуществами новейших функций dotnet. Используя мультитаргетинг, мы можем одновременно поддерживать разные версии платформы.
1. Проект
Для начала в файл проекта добавим нужные нам версии:
В .NET 8 добавлен новый тип коллекции — FrozenSet. Попробуем его использовать.
Этого можно достичь с помощью условных директив компилятора:
Нам бы хотелось использовать разные версии внешних зависимостей в зависимости от используемой версии платформы. Например, в .NET 7 - версию 7 EF Core, а в .NET 8 – превью версии 8.
* Здесь мы используем централизованное управление пакетами.
4. Сборка и публикация пакетов
В GitHub Actions единственное, что будет отличаться от обычного скрипта, это то, что вам необходимо убедиться, что вы указали все платформы, которые вы поддерживаете, на этапе настройки dotnet.
Источник: https://josef.codes/multi-targeting-your-nuget-packages/
Мультитаргетинг NuGet-Пакетов
При создании NuGet-пакета мы хотели бы использовать минимально возможную версию платформы (чтобы обеспечить максимальный охват), но также пользоваться преимуществами новейших функций dotnet. Используя мультитаргетинг, мы можем одновременно поддерживать разные версии платформы.
1. Проект
Для начала в файл проекта добавим нужные нам версии:
<Project>2. Код, зависимый от платформы
<PropertyGroup>
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
…
</PropertyGroup>
</Project>
В .NET 8 добавлен новый тип коллекции — FrozenSet. Попробуем его использовать.
Этого можно достичь с помощью условных директив компилятора:
private static readonly IReadOnlySet<Hamburger> AllItems;3. Внешние зависимости
static Hamburger()
{
#if NET8_0_OR_GREATER
AllItems = new HashSet<Hamburger>()
{
…
}.ToFrozenSet();
#else
AllItems = new HashSet<Hamburger>()
{
…
};
#endif
}
Нам бы хотелось использовать разные версии внешних зависимостей в зависимости от используемой версии платформы. Например, в .NET 7 - версию 7 EF Core, а в .NET 8 – превью версии 8.
* Здесь мы используем централизованное управление пакетами.
<Project>При сборке проекта для net7.0 используются зависимости, специфичные для .NET 7, и аналогично для .NET 8.
<PropertyGroup>
<ManagePackageVersionsCentrally>
true
</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<!-- общие зависимости -->
<PackageVersion Include="BenchmarkDotNet" Version="0.13.7"/>
…
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="7.0.10"/>
…
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.0-preview.7.23375.4"/>
…
</ItemGroup>
…
</Project>
4. Сборка и публикация пакетов
В GitHub Actions единственное, что будет отличаться от обычного скрипта, это то, что вам необходимо убедиться, что вы указали все платформы, которые вы поддерживаете, на этапе настройки dotnet.
steps:Больше ничего менять не надо, просто выполняйте
…
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: |
7.0.400
8.0.x
dotnet-quality: 'preview'
…
dotnet build
, dotnet pack
и dotnet publish
, как обычно.Источник: https://josef.codes/multi-targeting-your-nuget-packages/
👍10
День 1707. #ЗаметкиНаПолях
Дискриминируемые Объединения в C#
Дискриминируемые объединения (discriminated unions) – один из давних запросов на включение в язык C#. В F# они используются давно, а C#-разработчикам придется подождать их ещё немного.
Дискриминируемые объединения позволяют сообщить компилятору (и другим инструментам, таким как IDE), что данные могут быть одним из ряда предопределённых типов. Например, у вас может быть метод RegisterUser(), который возвращает класс User, UserAlreadyExists или InvalidUsername. Эти классы не обязаны наследовать друг от друга. Вы просто хотите поддерживать 3 потенциальных типа возврата, сообщить об этом языку и получать ошибки компилятора, если возвращаете другой тип.
В минимальных API ASP.NET Core типы Results<> и TypedResults позволяют определить, какие типы объектов могут быть возвращены. Например, здесь может быть возвращён тип результат ApiItem или Unauthorized:
Упрощённо класс Results с поддержкой 2 типов выглядит так:
Вы можете использовать аналогичный класс в вашем коде, например, для создания метода, который может возвращать int, bool или строку, но ничего больше:
Вне минимальных API вы можете использовать пакет OneOf, который позволяет работать с дискриминируемыми объединениями, выдаёт ошибки компилятора, когда сравнения не являются исчерпывающими, и т. д.
Источник: https://blog.maartenballiauw.be/post/2023/09/18/discriminated-unions-in-csharp.html
Дискриминируемые Объединения в C#
Дискриминируемые объединения (discriminated unions) – один из давних запросов на включение в язык C#. В F# они используются давно, а C#-разработчикам придется подождать их ещё немного.
Дискриминируемые объединения позволяют сообщить компилятору (и другим инструментам, таким как IDE), что данные могут быть одним из ряда предопределённых типов. Например, у вас может быть метод RegisterUser(), который возвращает класс User, UserAlreadyExists или InvalidUsername. Эти классы не обязаны наследовать друг от друга. Вы просто хотите поддерживать 3 потенциальных типа возврата, сообщить об этом языку и получать ошибки компилятора, если возвращаете другой тип.
В минимальных API ASP.NET Core типы Results<> и TypedResults позволяют определить, какие типы объектов могут быть возвращены. Например, здесь может быть возвращён тип результат ApiItem или Unauthorized:
app.MapGet("/item/{id}",Тип Results<> по сути представляет собой дискриминируемое объединение: возвращаемое значение будет одним из (в данном случае) двух типов, и механизм минимальных API может использовать эту информацию для возврата правильного типа.
async Task<Results<Ok<ApiItem>, Unauthorized>>(
[FromRoute]int id,
GroceryListDb db) => {
// …
return TypedResults.Ok(item);
});
Упрощённо класс Results с поддержкой 2 типов выглядит так:
public class Results<TResult1, TResult2>Очевидно, что аналогично выглядят классы для 3, 4 и т.д. типов результата. Используя неявные операторы, класс Results может быть создан из любого типа, поддерживающего преобразования.
{
private Results(object result)
{
Result = result;
}
public object Result { get; }
public static implicit operator
Results<TResult1, TResult2>(TResult1 result)
=> new(result);
public static implicit operator
Results<TResult1, TResult2>(TResult2 result)
=> new(result);
}
Вы можете использовать аналогичный класс в вашем коде, например, для создания метода, который может возвращать int, bool или строку, но ничего больше:
Results<int, bool, string> GetData()Если тип результата будет другим, IDE (и компилятор) сообщат вам об ошибке. Даже сопоставление по шаблону доступно (для свойства Result):
=> "Hello, world!";
var data = GetData();Недостатком является то, что если вы измените метод GetData(), чтобы он возвращал один из 4 типов (вместо 3), вы не получите ошибку компиляции в приведенном выше выражении switch. Это должно быть одним из преимуществ дискриминируемых объединений (если их когда-либо реализуют в языке): возможность получить инструментальную поддержку для этих случаев, информирующую вас о том, что у вас нет исчерпывающего соответствия для всех типов. Для минимальных API класс Results<> работает отлично. Использование результата является частью механики фреймворка, и в идеале вам никогда не придётся проводить исчерпывающее сравнение самостоятельно.
var type = data.Result switch
{
int => "int",
bool => "bool",
string => "string",
_ => throw new NotImplementedException()
};
Console.WriteLine(type);
Вне минимальных API вы можете использовать пакет OneOf, который позволяет работать с дискриминируемыми объединениями, выдаёт ошибки компилятора, когда сравнения не являются исчерпывающими, и т. д.
Источник: https://blog.maartenballiauw.be/post/2023/09/18/discriminated-unions-in-csharp.html
👍13
День 1708. #ЧтоНовенького
Использование Сервисов по Ключу в .NET 8
В DI-контейнер .NET 8 наконец-то добавили то, что уже много лет включено в другие контейнеры — использование сервиса по ключу, позволяющее нам внедрять несколько сервисов одного типа, но с разной реализацией. Ключ позволяет определить, какую реализацию использовать.
Допустим, у нас есть интерфейс
В .NET 8 можно разделить несколько сервисов с помощью ключа. Для IServiceCollection были добавлены методы расширения AddKeyedSingleton, AddKeyedScoped и AddKeyedTransient. Например:
Аналогично для контроллеров:
Использование Сервисов по Ключу в .NET 8
В DI-контейнер .NET 8 наконец-то добавили то, что уже много лет включено в другие контейнеры — использование сервиса по ключу, позволяющее нам внедрять несколько сервисов одного типа, но с разной реализацией. Ключ позволяет определить, какую реализацию использовать.
Допустим, у нас есть интерфейс
public interface IVehicleИ две реализации:
{
int Wheels { get; }
}
public class Car : IVehicleДо .NET 8 можно было добавлять несколько реализаций:
{
public int NoOfWheels => 4;
}
public class Bike : IVehicle
{
public int NoOfWheels => 2;
}
builder.Services.AddScoped<IVehicle, Car>();Однако, при внедрении использовалась последняя зарегистрированная реализация. Если бы мы хотели получить другие реализации, приходилось внедрять IEnumerable<IVehicle> и выбирать правильную реализацию уже в клиенте. Подробнее тут.
builder.Services.AddScoped<IVehicle, Bike>();
В .NET 8 можно разделить несколько сервисов с помощью ключа. Для IServiceCollection были добавлены методы расширения AddKeyedSingleton, AddKeyedScoped и AddKeyedTransient. Например:
builder.Services.AddKeyedScoped<IVehicle, Car>("car");Теперь в минимальных API можно использовать атрибут FromKeyedServices:
builder.Services.AddKeyedScoped<IVehicle, Bike>("bike");
app.MapGet("/api/carweels", (Ключ определяет, какую реализацию необходимо использовать.
[FromKeyedServices("car")] IVehicle v) =>
{
return Ok(new {
CarWheels = v.NoOfWheels
});
});
Аналогично для контроллеров:
[ApiController]Интерфейс IServiceProvider также получил методы GetRequiredKeyedService (и GetKeyedService, чтобы избежать исключения при null).
public class VehicleApiController : Controller
{
[HttpGet("carweels")]
public IActionResult CarWheels(
[FromKeyedServices("car")] IVehicle v)
{
return Ok(new {
CarWheels = v.NoOfWheels,
});
}
}
var car = _serviceProviderИсточник: https://www.roundthecode.com/dotnet-tutorials/keyed-services-dotnet-8-dependency-injection-update
.GetRequiredKeyedService<IVehicle>("car");
👍40👎2
День 1709. #ЗаметкиНаПолях
HashIDs. Что Это и Зачем Их Использовать?
В REST API для CRUD операций часто используются первичные ключи для доступа к ресурсу. Они часто реализуются как суррогатные ключи с использованием последовательных целочисленных значений. Это самый простой и эффективный способ указать данные/запись для извлечения.
Проблема в том, что это угроза безопасности API, т.к. мы показываем пользователю необработанные идентификаторы, особенно последовательные. Так мы даём пользователям возможность оценить количество записей и легко угадать значения других записей. Можно использовать GUID, но с ним есть свои проблемы.
Кроме того, у вас может быть унаследованная БД с уже определёнными идентификаторами. Например, в моей практике был случай, когда часть данных из результатов поиска, который был изначально доступен только зарегистрированным пользователям, было решено предоставлять публично. Получилось, что изначально закрытые целочисленные id теперь становились публично доступными.
Одним из решений является использование хэш-значений. Это эффективный подход для генерации неугадываемых непоследовательных идентификаторов, полученных из последовательных идентификаторов (например, целых чисел).
Теперь мы можем получить запись из нашего хранилища данных, где данные по-прежнему хранятся с использованием исходного последовательного идентификатора.
Как это работает?
HashIDs использует принцип преобразования десятичных чисел в шестнадцатеричные, однако base62 в качестве алфавита. Кроме того, алфавит перемешивается на основе уникального значения соли, которое может быть установлено пользователем. Это делает каждый алгоритм реализации уникальным и снижает риски безопасности. Идентификаторы нигде не сохраняются, а должны вычисляться каждый раз. Это позволяет нам менять соль без изменения данных. Таким образом для каждого запроса потребуется как минимум два преобразования: декодирование полученной из запроса строки в id и обратное кодирование id в строку при возврате результата клиенту. Скорость кодирования/декодирования измеряется в наносекундах, поэтому за производительность в подавляющем большинстве случаев переживать не придётся.
Итого
Хэши — это эффективный подход для приложений малого и среднего масштаба, которые не требуют более сложных стратегий, вроде идентификаторов Snowflake (объединение различных метаданных, таких как метки времени, идентификаторы сегментов и т. д.). И многие отраслевые решения, такие как GraphQL, используют простые хэши получая преимущества, изложенные выше.
Источник: https://stefandjokic.tech/blog
HashIDs. Что Это и Зачем Их Использовать?
В REST API для CRUD операций часто используются первичные ключи для доступа к ресурсу. Они часто реализуются как суррогатные ключи с использованием последовательных целочисленных значений. Это самый простой и эффективный способ указать данные/запись для извлечения.
Проблема в том, что это угроза безопасности API, т.к. мы показываем пользователю необработанные идентификаторы, особенно последовательные. Так мы даём пользователям возможность оценить количество записей и легко угадать значения других записей. Можно использовать GUID, но с ним есть свои проблемы.
Кроме того, у вас может быть унаследованная БД с уже определёнными идентификаторами. Например, в моей практике был случай, когда часть данных из результатов поиска, который был изначально доступен только зарегистрированным пользователям, было решено предоставлять публично. Получилось, что изначально закрытые целочисленные id теперь становились публично доступными.
Одним из решений является использование хэш-значений. Это эффективный подход для генерации неугадываемых непоследовательных идентификаторов, полученных из последовательных идентификаторов (например, целых чисел).
[HttpGet]Приведенный выше метод API принимает идентификатор аргумента строкового типа. Библиотека HashIds (недавно переименованная в Sqids) предоставляет готовую к использованию реализацию с функцией Decode, которая преобразует строковый идентификатор (предварительно полученный с помощью функции Encode) обратно в исходный числовой идентификатор.
public IActionResult Get([FromRoute] string id)
{
int[] intId = _hashids.Decode(id);
if (intId.Length == 0) return NotFound();
var user = _userService.GetUser(intId[0]);
if (user is null) return NotFound();
return Ok(user);
}
Теперь мы можем получить запись из нашего хранилища данных, где данные по-прежнему хранятся с использованием исходного последовательного идентификатора.
Как это работает?
HashIDs использует принцип преобразования десятичных чисел в шестнадцатеричные, однако base62 в качестве алфавита. Кроме того, алфавит перемешивается на основе уникального значения соли, которое может быть установлено пользователем. Это делает каждый алгоритм реализации уникальным и снижает риски безопасности. Идентификаторы нигде не сохраняются, а должны вычисляться каждый раз. Это позволяет нам менять соль без изменения данных. Таким образом для каждого запроса потребуется как минимум два преобразования: декодирование полученной из запроса строки в id и обратное кодирование id в строку при возврате результата клиенту. Скорость кодирования/декодирования измеряется в наносекундах, поэтому за производительность в подавляющем большинстве случаев переживать не придётся.
Итого
Хэши — это эффективный подход для приложений малого и среднего масштаба, которые не требуют более сложных стратегий, вроде идентификаторов Snowflake (объединение различных метаданных, таких как метки времени, идентификаторы сегментов и т. д.). И многие отраслевые решения, такие как GraphQL, используют простые хэши получая преимущества, изложенные выше.
Источник: https://stefandjokic.tech/blog
👍25
День 1710. #ЗаметкиНаПолях #Debugging
Правила Отладки: Заставь Его Упасть. Начало
В своей книге «Совершенный Код» Стив МакКоннелл предлагает научный метод отладки. Он состоит из следующих шагов:
- Стабилизировать ошибку
- Найти источник ошибки
- Исправить дефект
- Проверить исправление
- Найти похожие ошибки
Как видите, начальный этап зависит от достижения повторяемости. Диагностика дефекта становится более управляемой, когда его можно стабилизировать, обеспечивая последовательное и надёжное возникновение. Диагностика непредсказуемого дефекта - сложная задача. Такая ошибка обычно связана либо с неточностями инициализации, либо с нарушениями синхронизации. Стабилизация такой ошибки включает в себя не просто создание теста, вызывающего ошибку, но и уточнение его до простейшей формы, при этом все равно выдающей ошибку.
Есть три основные причины стабилизировать ошибку:
- Возможность наблюдать, как возникает ошибка.
- Сосредоточиться на вероятных причинах её возникновения.
- Впоследствии это надёжная проверку того, исправили ли вы ошибку.
Просто сделай это «снова»
Воспроизвести ошибку один раз недостаточно. Задокументируйте действия, приводящие к ошибке, и убедитесь, что она возникает при каждом повторении. Однако в определённых сценариях возникновение ошибки может привести к причинению вреда или нежелательным последствиям. В таких случаях необходимо внести коррективы, чтобы свести к минимуму степень потенциального ущерба, стремясь при этом максимально сохранить суть исходной системы и последовательность действий.
Часто необходимые действия кратки и минимальны. Иногда порядок событий может быть несложным, однако необходима значительная подготовительная работа. Т.к. ошибки могут зависеть от сложных состояний системы, важно наблюдать и документировать состояние системы, прежде чем приступать к выполнению последовательности действий.
Стимулируйте неудачу
Если последовательность действий для возникновения сбоя длинная, оптимизация процесса за счёт автоматизации может оказаться выгодной. Важно различать стимуляцию неудачи и искусственную симуляцию неудачи. Допустимо автоматизированное воспроизведение обстоятельств, которые приводят к сбою, но желательно избегать искусственного воспроизведения самого механизма сбоя.
В случаях непредсказуемых ошибок вы можете предположить, что за сбой ответственен определённый механизм. В ответ вы можете создать конфигурацию, реализующую этот механизм. Либо, если ошибка возникает из-за состояния удалённой системы, вы можете попытаться эмулировать эту систему локально. Так вы пытаетесь смоделировать сбой, т.е. воссоздать его с помощью альтернативного подхода или в отдельно взятой системе.
Часто это неэффективно. Ваша смоделированная установка может демонстрировать постоянную безупречную воспроизводимость ошибки или, что более проблематично, столкнуться с новым видом сбоя, который отвлечёт ваше внимание от исходной ошибки.
У вас уже есть ошибка, не создавайте новые. Используйте инструменты для изучения источника проблемы, но воздержитесь от изменения основного механизма, поскольку он является самой причиной сбоя.
Если ошибка может быть воспроизведена в нескольких системах, это свидетельствует о недостатках проектирования, а не об изолированной неисправности системы. Воссоздание проблемы в конкретных конфигурациях при исключении других помогает сузить круг потенциальных причин. Но если вам трудно быстро воспроизвести ошибку, не моделируйте её возникновение. Это создаёт новую конфигурацию, а не проверяет ту, в которой ошибка возникла.
Это не значит, что следует избегать автоматизации тестирования. Оно может ускорить возникновение периодических проблем. Однако любые вносимые корректировки не должны изменять то, как система выходит из строя, а, скорее, влиять на частоту возникновения ошибки. Также соблюдайте осторожность, чтобы предотвратить чрезмерные модификации, которые потенциально могут привести к новым осложнениям.
Окончание следует…
Источник: https://dev.to/rajasegar/debugging-rules-make-it-fail-33c0
Правила Отладки: Заставь Его Упасть. Начало
В своей книге «Совершенный Код» Стив МакКоннелл предлагает научный метод отладки. Он состоит из следующих шагов:
- Стабилизировать ошибку
- Найти источник ошибки
- Исправить дефект
- Проверить исправление
- Найти похожие ошибки
Как видите, начальный этап зависит от достижения повторяемости. Диагностика дефекта становится более управляемой, когда его можно стабилизировать, обеспечивая последовательное и надёжное возникновение. Диагностика непредсказуемого дефекта - сложная задача. Такая ошибка обычно связана либо с неточностями инициализации, либо с нарушениями синхронизации. Стабилизация такой ошибки включает в себя не просто создание теста, вызывающего ошибку, но и уточнение его до простейшей формы, при этом все равно выдающей ошибку.
Есть три основные причины стабилизировать ошибку:
- Возможность наблюдать, как возникает ошибка.
- Сосредоточиться на вероятных причинах её возникновения.
- Впоследствии это надёжная проверку того, исправили ли вы ошибку.
Просто сделай это «снова»
Воспроизвести ошибку один раз недостаточно. Задокументируйте действия, приводящие к ошибке, и убедитесь, что она возникает при каждом повторении. Однако в определённых сценариях возникновение ошибки может привести к причинению вреда или нежелательным последствиям. В таких случаях необходимо внести коррективы, чтобы свести к минимуму степень потенциального ущерба, стремясь при этом максимально сохранить суть исходной системы и последовательность действий.
Часто необходимые действия кратки и минимальны. Иногда порядок событий может быть несложным, однако необходима значительная подготовительная работа. Т.к. ошибки могут зависеть от сложных состояний системы, важно наблюдать и документировать состояние системы, прежде чем приступать к выполнению последовательности действий.
Стимулируйте неудачу
Если последовательность действий для возникновения сбоя длинная, оптимизация процесса за счёт автоматизации может оказаться выгодной. Важно различать стимуляцию неудачи и искусственную симуляцию неудачи. Допустимо автоматизированное воспроизведение обстоятельств, которые приводят к сбою, но желательно избегать искусственного воспроизведения самого механизма сбоя.
В случаях непредсказуемых ошибок вы можете предположить, что за сбой ответственен определённый механизм. В ответ вы можете создать конфигурацию, реализующую этот механизм. Либо, если ошибка возникает из-за состояния удалённой системы, вы можете попытаться эмулировать эту систему локально. Так вы пытаетесь смоделировать сбой, т.е. воссоздать его с помощью альтернативного подхода или в отдельно взятой системе.
Часто это неэффективно. Ваша смоделированная установка может демонстрировать постоянную безупречную воспроизводимость ошибки или, что более проблематично, столкнуться с новым видом сбоя, который отвлечёт ваше внимание от исходной ошибки.
У вас уже есть ошибка, не создавайте новые. Используйте инструменты для изучения источника проблемы, но воздержитесь от изменения основного механизма, поскольку он является самой причиной сбоя.
Если ошибка может быть воспроизведена в нескольких системах, это свидетельствует о недостатках проектирования, а не об изолированной неисправности системы. Воссоздание проблемы в конкретных конфигурациях при исключении других помогает сузить круг потенциальных причин. Но если вам трудно быстро воспроизвести ошибку, не моделируйте её возникновение. Это создаёт новую конфигурацию, а не проверяет ту, в которой ошибка возникла.
Это не значит, что следует избегать автоматизации тестирования. Оно может ускорить возникновение периодических проблем. Однако любые вносимые корректировки не должны изменять то, как система выходит из строя, а, скорее, влиять на частоту возникновения ошибки. Также соблюдайте осторожность, чтобы предотвратить чрезмерные модификации, которые потенциально могут привести к новым осложнениям.
Окончание следует…
Источник: https://dev.to/rajasegar/debugging-rules-make-it-fail-33c0
👍8
День 1711. #ЗаметкиНаПолях #Debugging
Правила Отладки: Заставь Его Упасть. Окончание
Начало
Неконтролируемое состояние
Задача «дать ему упасть» становится значительно сложнее, когда сбой происходит периодически. Хотя вы можете точно понять, какие шаги привели к первоначальной неудаче, последовательное её воспроизведение остаётся невозможным – возможно, это происходит только раз из 5, 10 или 100 попыток.
Следует признать, что, несмотря на понимание причин, о вам не хватает исчерпывающих знаний обо всех точных условиях. Овладение этими разнообразными условиями позволит вам постоянно вызывать сбой. В ситуациях, когда сбой непостоянен, вы должны тщательно проанализировать его, не обращая внимания на многочисленные случаи, когда его не возникло. Основная стратегия предполагает сбор полных данных во время каждого запуска, что позволяет провести углублённый анализ после подтверждения сбоя. Этого можно достичь, генерируя обширные выходные данные системы во время её работы и собирая эту информацию в специальном «журнале отладки».
Тщательно изучая накопленные данные, вы можете легко сравнить неудачный запуск с успешным. Если удастся собрать соответствующую информацию, вы, скорее всего, заметите различия между ними. Обратите внимание на факторы, характерные только для случаев отказа. Даже если сбой происходит периодически, этот подход позволяет систематически выявлять и документировать происшествия, тем самым позволяя устранять их так, как если бы они происходили постоянно.
Лаять не на то дерево
При периодических проблемах вы можете начать замечать закономерности в своих действиях, которые кажутся связанными со сбоем. Важно проявлять осторожность и не зацикливаться на этих шаблонах. Часто совпадения могут заставить поверить, что одно условие увеличивает вероятность возникновения проблемы по сравнению с другим. Собрав значительный объем информации, вы сможете отличить элементы, постоянно связанные с ошибкой, от тех, которые никогда с ней не были связаны.
Несомненно, случайность усложняет процесс подтверждения исправления. Например, если тест показывает процент неудач в 10%, а ваше вмешательство снижает его до 3% — но вы прекращаете тестирование после 28 попыток — вы можете поверить, что проблема решена, даже если это не так.
Важно определить последовательность событий, неизменно приводящих к сбою, даже если возникновение этой последовательности носит случайных характер. Поэтому после реализации потенциального исправления продолжайте тестирование, пока последовательность действий не выяснится. Если последовательность проявляется без соответствующего сбоя, вы успешно исправили ошибку. Не делайте преждевременных выводов, если последовательность ещё не проявилась.
Черные лебеди
Легко просто игнорировать предупреждающие знаки и аргументы других людей (клиентов или тестировщиков), которые настаивают на существовании ошибок.
Знайте, что «это» может случиться
Отсутствие доказательств не означает доказательства отсутствия. Люди отрицали существование чёрных лебедей, пока не увидели их. В мире ПО высока вероятность возникновения неожиданных событий. И когда вы видите одного чёрного лебедя, пришло время отказаться от своих предположений и подумать о разработке новой стратегии для поиска новых.
Итого
Если вы понятия не имеете, что может быть не так, жизнь становится сложнее! Начните с того, что убедитесь, что вы можете обеспечить постоянное проявление ошибки. Потратьте время на подготовку входных данных и настройку параметров, которые последовательно вызывают проблему. Затем упакуйте эти шаги в упрощённую процедуру, которая облегчает лёгкое и автоматизированное выполнение. Когда вы имеете дело со сложной ошибкой, вы обнаружите, что неоднократно воспроизводите её по мере выяснения основной причины. Таким образом, оптимизация процесса воспроизведения в итоге сэкономит вам время. Столкнувшись с ошибкой, которая возникает случайно, приложите усилия к пониманию причин её случайного характера.
Источник: https://dev.to/rajasegar/debugging-rules-make-it-fail-33c0
Правила Отладки: Заставь Его Упасть. Окончание
Начало
Неконтролируемое состояние
Задача «дать ему упасть» становится значительно сложнее, когда сбой происходит периодически. Хотя вы можете точно понять, какие шаги привели к первоначальной неудаче, последовательное её воспроизведение остаётся невозможным – возможно, это происходит только раз из 5, 10 или 100 попыток.
Следует признать, что, несмотря на понимание причин, о вам не хватает исчерпывающих знаний обо всех точных условиях. Овладение этими разнообразными условиями позволит вам постоянно вызывать сбой. В ситуациях, когда сбой непостоянен, вы должны тщательно проанализировать его, не обращая внимания на многочисленные случаи, когда его не возникло. Основная стратегия предполагает сбор полных данных во время каждого запуска, что позволяет провести углублённый анализ после подтверждения сбоя. Этого можно достичь, генерируя обширные выходные данные системы во время её работы и собирая эту информацию в специальном «журнале отладки».
Тщательно изучая накопленные данные, вы можете легко сравнить неудачный запуск с успешным. Если удастся собрать соответствующую информацию, вы, скорее всего, заметите различия между ними. Обратите внимание на факторы, характерные только для случаев отказа. Даже если сбой происходит периодически, этот подход позволяет систематически выявлять и документировать происшествия, тем самым позволяя устранять их так, как если бы они происходили постоянно.
Лаять не на то дерево
При периодических проблемах вы можете начать замечать закономерности в своих действиях, которые кажутся связанными со сбоем. Важно проявлять осторожность и не зацикливаться на этих шаблонах. Часто совпадения могут заставить поверить, что одно условие увеличивает вероятность возникновения проблемы по сравнению с другим. Собрав значительный объем информации, вы сможете отличить элементы, постоянно связанные с ошибкой, от тех, которые никогда с ней не были связаны.
Несомненно, случайность усложняет процесс подтверждения исправления. Например, если тест показывает процент неудач в 10%, а ваше вмешательство снижает его до 3% — но вы прекращаете тестирование после 28 попыток — вы можете поверить, что проблема решена, даже если это не так.
Важно определить последовательность событий, неизменно приводящих к сбою, даже если возникновение этой последовательности носит случайных характер. Поэтому после реализации потенциального исправления продолжайте тестирование, пока последовательность действий не выяснится. Если последовательность проявляется без соответствующего сбоя, вы успешно исправили ошибку. Не делайте преждевременных выводов, если последовательность ещё не проявилась.
Черные лебеди
Легко просто игнорировать предупреждающие знаки и аргументы других людей (клиентов или тестировщиков), которые настаивают на существовании ошибок.
Знайте, что «это» может случиться
Отсутствие доказательств не означает доказательства отсутствия. Люди отрицали существование чёрных лебедей, пока не увидели их. В мире ПО высока вероятность возникновения неожиданных событий. И когда вы видите одного чёрного лебедя, пришло время отказаться от своих предположений и подумать о разработке новой стратегии для поиска новых.
Итого
Если вы понятия не имеете, что может быть не так, жизнь становится сложнее! Начните с того, что убедитесь, что вы можете обеспечить постоянное проявление ошибки. Потратьте время на подготовку входных данных и настройку параметров, которые последовательно вызывают проблему. Затем упакуйте эти шаги в упрощённую процедуру, которая облегчает лёгкое и автоматизированное выполнение. Когда вы имеете дело со сложной ошибкой, вы обнаружите, что неоднократно воспроизводите её по мере выяснения основной причины. Таким образом, оптимизация процесса воспроизведения в итоге сэкономит вам время. Столкнувшись с ошибкой, которая возникает случайно, приложите усилия к пониманию причин её случайного характера.
Источник: https://dev.to/rajasegar/debugging-rules-make-it-fail-33c0
👍6
День 1712. #ЧтоНовенького
Windows Dev Drive
Dev Drive — это новая форма хранилища в Windows 11, позволяющая повысить производительность ключевых рабочих нагрузок разработчиков.
Dev Drive использует технологию ReFS для целевой оптимизации файловой системы и обеспечения большего контроля над настройками тома хранилища и безопасностью, включая определение доверия, настройку антивируса и административный контроль над тем, какие фильтры подключены. Согласно бенчмаркам Microsoft, это обеспечивает до 30% прироста производительности сборок и других диско-нагруженных операций.
Windows использует NTFS для системного диска и по умолчанию для большинства несъёмных дисков. Устойчивая файловая система (Resilient File System - ReFS) — это новый формат файловой системы от Microsoft, разработанный для обеспечения максимальной доступности данных, эффективного масштабирования для больших наборов данных при различных рабочих нагрузках и обеспечения целостности данных и устойчивости к повреждению. Он направлен на решение расширяющегося набора сценариев хранения данных и создание основы для будущих инноваций.
Что хранить на Dev Drive?
- Репозитории исходного кода и файлы проекта
- Кэши пакетов
- Артефакты сборки и промежуточные файлы
Dev Drive не предназначен для хранения инструментов разработчика, таких как:
- Visual Studio
- MSBuild
- .NET SDK
- Windows SDK, etc.
Эти утилиты должны размещаться на основном диске C:\.
Странно, что ничего не сказано про файлы баз данных, которые теоретически должны подходить под диско-нагруженные операции. Однако, я не смог найти советов ни за, ни против их размещения на Dev Drive. Если кто-нибудь что-нибудь об этом знает или был опыт, отпишитесь в комментариях.
Риски безопасности и доверия в отношении Dev Drive
Обычно существует компромисс между производительностью и безопасностью. Использование Dev Drive передаёт контроль над этим балансом в руки разработчиков и администраторов по безопасности, которые несут ответственность за выбор прикреплённых фильтров и параметров сканирования Microsoft Defender.
Антивирусные фильтры по умолчанию включены для Dev Drive. Microsoft Defender по умолчанию использует новый параметр performance mode (режим производительности) на Dev Drive, делая акцент на производительности и обеспечивая при этом безопасную альтернативу простому исключению папок из-под анализа антивируса.
«Доверенный» Dev Drive
Диски Dev Drive автоматически обозначаются как доверенные с использованием флага, хранящегося в системном реестре во время исходного форматирования, что по умолчанию обеспечивает максимально возможную производительность. Доверие диску означает, что разработчик, использующий этот том, полностью уверен в безопасности хранящегося там контента. Разработчик берёт на себя ответственность за управление безопасностью хранимого контента, чтобы получить дополнительную производительность.
Dev Drive, помеченный как доверенный, является сигналом для Microsoft Defender для работы в режиме производительности. Это обеспечивает баланс между защитой от угроз и производительностью. Для повышения уровня защиты Microsoft Defender также предлагает «Режим защиты в реальном времени» (Real-time protection mode). Защита в режиме реального времени по-прежнему будет включена на всех остальных томах.
Источники:
- https://blogs.windows.com/windowsdeveloper/2023/06/01/dev-drive-performance-security-and-control-for-developers/
- https://learn.microsoft.com/en-us/windows/dev-drive/
Windows Dev Drive
Dev Drive — это новая форма хранилища в Windows 11, позволяющая повысить производительность ключевых рабочих нагрузок разработчиков.
Dev Drive использует технологию ReFS для целевой оптимизации файловой системы и обеспечения большего контроля над настройками тома хранилища и безопасностью, включая определение доверия, настройку антивируса и административный контроль над тем, какие фильтры подключены. Согласно бенчмаркам Microsoft, это обеспечивает до 30% прироста производительности сборок и других диско-нагруженных операций.
Windows использует NTFS для системного диска и по умолчанию для большинства несъёмных дисков. Устойчивая файловая система (Resilient File System - ReFS) — это новый формат файловой системы от Microsoft, разработанный для обеспечения максимальной доступности данных, эффективного масштабирования для больших наборов данных при различных рабочих нагрузках и обеспечения целостности данных и устойчивости к повреждению. Он направлен на решение расширяющегося набора сценариев хранения данных и создание основы для будущих инноваций.
Что хранить на Dev Drive?
- Репозитории исходного кода и файлы проекта
- Кэши пакетов
- Артефакты сборки и промежуточные файлы
Dev Drive не предназначен для хранения инструментов разработчика, таких как:
- Visual Studio
- MSBuild
- .NET SDK
- Windows SDK, etc.
Эти утилиты должны размещаться на основном диске C:\.
Странно, что ничего не сказано про файлы баз данных, которые теоретически должны подходить под диско-нагруженные операции. Однако, я не смог найти советов ни за, ни против их размещения на Dev Drive. Если кто-нибудь что-нибудь об этом знает или был опыт, отпишитесь в комментариях.
Риски безопасности и доверия в отношении Dev Drive
Обычно существует компромисс между производительностью и безопасностью. Использование Dev Drive передаёт контроль над этим балансом в руки разработчиков и администраторов по безопасности, которые несут ответственность за выбор прикреплённых фильтров и параметров сканирования Microsoft Defender.
Антивирусные фильтры по умолчанию включены для Dev Drive. Microsoft Defender по умолчанию использует новый параметр performance mode (режим производительности) на Dev Drive, делая акцент на производительности и обеспечивая при этом безопасную альтернативу простому исключению папок из-под анализа антивируса.
«Доверенный» Dev Drive
Диски Dev Drive автоматически обозначаются как доверенные с использованием флага, хранящегося в системном реестре во время исходного форматирования, что по умолчанию обеспечивает максимально возможную производительность. Доверие диску означает, что разработчик, использующий этот том, полностью уверен в безопасности хранящегося там контента. Разработчик берёт на себя ответственность за управление безопасностью хранимого контента, чтобы получить дополнительную производительность.
Dev Drive, помеченный как доверенный, является сигналом для Microsoft Defender для работы в режиме производительности. Это обеспечивает баланс между защитой от угроз и производительностью. Для повышения уровня защиты Microsoft Defender также предлагает «Режим защиты в реальном времени» (Real-time protection mode). Защита в режиме реального времени по-прежнему будет включена на всех остальных томах.
Источники:
- https://blogs.windows.com/windowsdeveloper/2023/06/01/dev-drive-performance-security-and-control-for-developers/
- https://learn.microsoft.com/en-us/windows/dev-drive/
👍10
День 1713. #ВопросыНаСобеседовании #Многопоточность
Самые часто задаваемые вопросы на собеседовании по C#
24. Чем задачи в C# отличаются от традиционных потоков? Объясните преимущества и сценарии, в которых задачи предпочтительнее прямого создания потоков.
И задачи (Task), и потоки (Thread) используются в C# для асинхронного и параллельного программирования. Однако между ними есть некоторые ключевые различия:
1) Уровень абстракции.
Задачи представляют собой абстракцию более высокого уровня, построенную на основе потоков и фокусирующуюся на выполняемой работе, а не на низкоуровневом управлении потоками. Потоки — это концепция более низкого уровня, позволяющая более детально контролировать детали выполнения.
2) Управление ресурсами.
Задачи используют пул потоков .NET для более эффективного управления рабочими потоками, сокращая накладные расходы на создание и уничтожение потоков. Потоки, создаваемые индивидуально для каждого действия, требуют больше ресурсов и плохо масштабируются для больших рабочих нагрузок.
3) Время жизни.
Потоки задач — это фоновые потоки, время жизни которых управляется системой. Thread может быть как фоновым, так и иметь приоритет, а время его существования контролируется разработчиком.
4) Асинхронное программирование.
Задачи интегрируются с шаблоном async/await для упрощения асинхронного программирования. Потоки требуют ручной синхронизации при координации с асинхронными операциями.
5) Продолжения.
Задачи позволяют упростить цепочку работ с помощью ContinueWith(), позволяя планировать выполнение работы после завершения предыдущей задачи. Для таких сценариев потоки требуют ручной синхронизации с использованием примитивов синхронизации.
6) Отмена.
Задачи предоставляют встроенный механизм отмены с использованием CancellationToken, предлагающий стандартизированный способ отмены и распространения запросов на отмену. Потоки должны реализовывать собственную логику отмены с использованием общих флагов или других механизмов синхронизации.
7) Обработка исключений.
Задачи лучше обеспечивают обработку исключений, объединяя исключения из нескольких задач и распространяя их в вызывающий контекст. Для потоков требуются более сложные механизмы обработки исключений, возникающих в дочерних потоках.
Когда использовать задачи:
- При работе с асинхронными или параллельными рабочими нагрузками. Можно извлечь выгоду из улучшенного управления ресурсами и масштабируемости ThreadPool.
- При использовании шаблона async/await для асинхронного программирования.
- Необходима координация работы с использованием продолжений.
- Необходим встроенный механизм отмены и стандартизированная обработка исключений.
Когда использовать потоки:
Вам нужен детальный контроль над выполнением, или у вас особые требования, которые не могут быть удовлетворены с помощью абстракций более высокого уровня (Task):
- Долгоживущие единицы работы: фоновые сервисы или сложные расчеты, требующие большего контроля над выполнением работ.
- Детальный контроль над выполнением потоков: установка приоритета или тонкая настройка синхронизации и прерываний.
- Низкоуровневое программирование.
- Взаимодействие с неуправляемым кодом.
Итого
Задачи предоставляют более высокоуровневую и более гибкую абстракцию для параллельного и асинхронного программирования, упрощая код и повышая производительность во многих сценариях. Однако могут быть особые случаи, когда детальный контроль и настройка, предоставляемые классом Thread, по-прежнему необходимы или полезны.
Источник: https://dev.to/bytehide/c-multithreading-interview-questions-and-answers-4opj
Самые часто задаваемые вопросы на собеседовании по C#
24. Чем задачи в C# отличаются от традиционных потоков? Объясните преимущества и сценарии, в которых задачи предпочтительнее прямого создания потоков.
И задачи (Task), и потоки (Thread) используются в C# для асинхронного и параллельного программирования. Однако между ними есть некоторые ключевые различия:
1) Уровень абстракции.
Задачи представляют собой абстракцию более высокого уровня, построенную на основе потоков и фокусирующуюся на выполняемой работе, а не на низкоуровневом управлении потоками. Потоки — это концепция более низкого уровня, позволяющая более детально контролировать детали выполнения.
2) Управление ресурсами.
Задачи используют пул потоков .NET для более эффективного управления рабочими потоками, сокращая накладные расходы на создание и уничтожение потоков. Потоки, создаваемые индивидуально для каждого действия, требуют больше ресурсов и плохо масштабируются для больших рабочих нагрузок.
3) Время жизни.
Потоки задач — это фоновые потоки, время жизни которых управляется системой. Thread может быть как фоновым, так и иметь приоритет, а время его существования контролируется разработчиком.
4) Асинхронное программирование.
Задачи интегрируются с шаблоном async/await для упрощения асинхронного программирования. Потоки требуют ручной синхронизации при координации с асинхронными операциями.
5) Продолжения.
Задачи позволяют упростить цепочку работ с помощью ContinueWith(), позволяя планировать выполнение работы после завершения предыдущей задачи. Для таких сценариев потоки требуют ручной синхронизации с использованием примитивов синхронизации.
6) Отмена.
Задачи предоставляют встроенный механизм отмены с использованием CancellationToken, предлагающий стандартизированный способ отмены и распространения запросов на отмену. Потоки должны реализовывать собственную логику отмены с использованием общих флагов или других механизмов синхронизации.
7) Обработка исключений.
Задачи лучше обеспечивают обработку исключений, объединяя исключения из нескольких задач и распространяя их в вызывающий контекст. Для потоков требуются более сложные механизмы обработки исключений, возникающих в дочерних потоках.
Когда использовать задачи:
- При работе с асинхронными или параллельными рабочими нагрузками. Можно извлечь выгоду из улучшенного управления ресурсами и масштабируемости ThreadPool.
- При использовании шаблона async/await для асинхронного программирования.
- Необходима координация работы с использованием продолжений.
- Необходим встроенный механизм отмены и стандартизированная обработка исключений.
Когда использовать потоки:
Вам нужен детальный контроль над выполнением, или у вас особые требования, которые не могут быть удовлетворены с помощью абстракций более высокого уровня (Task):
- Долгоживущие единицы работы: фоновые сервисы или сложные расчеты, требующие большего контроля над выполнением работ.
- Детальный контроль над выполнением потоков: установка приоритета или тонкая настройка синхронизации и прерываний.
- Низкоуровневое программирование.
- Взаимодействие с неуправляемым кодом.
Итого
Задачи предоставляют более высокоуровневую и более гибкую абстракцию для параллельного и асинхронного программирования, упрощая код и повышая производительность во многих сценариях. Однако могут быть особые случаи, когда детальный контроль и настройка, предоставляемые классом Thread, по-прежнему необходимы или полезны.
Источник: https://dev.to/bytehide/c-multithreading-interview-questions-and-answers-4opj
👍31
День 1714. #ЗаметкиНаПолях
Как Получить Значение Типа по Умолчанию во Время Выполнения
При написании кода можно использовать значение default(T). Но что, если вы хотите сделать то же самое во время выполнения? Как получить значение по умолчанию для любого System.Type? (Допустим, вам это понадобилось)
В сети можно найти множество неправильных ответов. Например, этот:
В C# 10 вы можете создать структуру с конструктором по умолчанию:
1. Использовать System.Linq.Expression, но это медленно (~20мс):
Как Получить Значение Типа по Умолчанию во Время Выполнения
При написании кода можно использовать значение default(T). Но что, если вы хотите сделать то же самое во время выполнения? Как получить значение по умолчанию для любого System.Type? (Допустим, вам это понадобилось)
В сети можно найти множество неправильных ответов. Например, этот:
object? GetDefaultValue(Type t) =>Это отлично работает для ссылочных типов и большинства типов значений. Но Activator.CreateInstance(T) — это не то же самое, что default(T), когда T является типом значения. Activator.CreateInstance(T) аналогичен new T(). То есть, он вызывает конструктор по умолчанию. default(T) не вызывает конструктор по умолчанию. Он инициализирует все поля значениями по умолчанию.
t.IsValueType
? Activator.CreateInstance(t)
: null;
В C# 10 вы можете создать структуру с конструктором по умолчанию:
struct SampleПосмотрим на разницу между default(Sample) и new Sample():
{
public int Value { get; }
public Sample() => Value = 1;
}
default(Sample).Value // 0Так как же получить default(T) во время выполнения?
new Sample().Value // 1
Activator
.CreateInstance<Sample>()
.Value // 1
1. Использовать System.Linq.Expression, но это медленно (~20мс):
object? GetDefaultValue(Type t)2. Обобщённый класс со статическим свойством, которое возвращает значение обобщённого типа по умолчанию. Это быстрее (~2мс):
{
if (t.IsValueType)
{
var defExpr = Expression.Default(t);
return Expression
.Lambda(defExpr)
.Compile()
.DynamicInvoke();
}
return null;
}
object? GetDefaultValue(Type t)3. Начиная с.NET Core, вы можете использовать System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject, чтобы получить неинициализированный экземпляр (~30нс):
{
if (t.IsValueType)
{
var defType = typeof(DefaultProvider<>)
.MakeGenericType(t);
return defType
.InvokeMember("Value",
BindingFlags.Public |
BindingFlags.Static |
BindingFlags.GetProperty,
binder: null,
target: null,
args: null,
culture: null);
}
return null;
}
private static class DefaultProvider<T>
{
public static T? Value => default;
}
object? GetDefaultValue(Type t)Можно использовать любой из этих методов, чтобы получить значение по умолчанию:
{
if (t.IsValueType)
return RuntimeHelpers
.GetUninitializedObject(t);
return null;
}
((Sample)GetDefaultValue(typeof(Sample)))Источник: https://www.meziantou.net/get-the-default-value-of-a-type-at-runtime.htm
.Value // 0
👍17
День 1715. #ЗаметкиНаПолях
Виды Структур в C#. Начало
Рассмотрим, в чём разница между структурой, структурой для чтения и ref-структурой, а также, какие ограничения есть у этих типов.
1. Структура
Все в той или иной степени ими пользовались. Структура — это тип значения, который в идеале должен представлять одно логическое значение: DateTime, int, double или TimeSpan, либо пользовательские, вроде Point2D, которая может состоять из координат x и y. В документации Microsoft есть подсказка, когда не следует использовать структуры: если экземпляр придётся часто упаковывать.
Обычно типы значений, такие как структура, находятся в стеке. Стек — это хороший способ моделирования времени жизни переменной. Если вы объявите int в функции, он будет жить только в этой области:
Структуры позволяют многое из того, что допускает класс, но с некоторыми ключевыми отличиями:
- Структура не может наследовать от других классов или структур (возможны интерфейсы)
- Структура не может иметь деструктор.
Пример структуры:
readonly struct были представлены в C# 7.2. Основная идея состоит в том, чтобы сделать структуру неизменяемой. Конечно, вы можете сделать это без модификатора только для чтения (например, DateTime существует с самого начала), но компилятор поможет вам, если вы нарушите логику только для чтения.
Пример выше выдаст несколько ошибок компилятора, если добавить readonly к объявлению структуры. Причина проста: во-первых, мы должны объявить все поля как readonly (иначе любой вызывающий объект мог бы просто изменить их). Во-вторых, метод ShiftToGrayscale по-прежнему изменяет внутреннее состояние, поэтому его тоже надо изменить на выдачу новой структуры:
- Повышенная тестируемость
- Потокобезопасность.
- Атомарность неудачи.
- Отсутствие скрытых побочных эффектов.
Компилятор попытается помочь вам с неизменяемостью, но не сможет её гарантировать. Если в структуре есть список, его члены всё равно можно будет изменять:
Источник: https://steven-giesel.com/blogPost/2a52cd8d-b3b2-42e4-87e8-d6dc14147ddb
Виды Структур в C#. Начало
Рассмотрим, в чём разница между структурой, структурой для чтения и ref-структурой, а также, какие ограничения есть у этих типов.
1. Структура
Все в той или иной степени ими пользовались. Структура — это тип значения, который в идеале должен представлять одно логическое значение: DateTime, int, double или TimeSpan, либо пользовательские, вроде Point2D, которая может состоять из координат x и y. В документации Microsoft есть подсказка, когда не следует использовать структуры: если экземпляр придётся часто упаковывать.
Обычно типы значений, такие как структура, находятся в стеке. Стек — это хороший способ моделирования времени жизни переменной. Если вы объявите int в функции, он будет жить только в этой области:
public void MyFunc()Здесь a существует только внутри MyFunc, и только на стеке. Но если мы используем какой-либо тип значения, например, в качестве поля в классе, тогда эта переменная должна находиться в куче, поскольку её родитель находится в куче.
{
int a = 2;
}
Структуры позволяют многое из того, что допускает класс, но с некоторыми ключевыми отличиями:
- Структура не может наследовать от других классов или структур (возможны интерфейсы)
- Структура не может иметь деструктор.
Пример структуры:
public struct Color2. Структура только для чтения
{
public byte Red;
public byte Green;
public byte Blue;
public Color() {
Red = 0; Green = 0; Blue = 0;
}
public void ShiftToGrayscale()
{
var avg = (byte)((Red + Green + Blue) / 3);
Red = Green = Blue = avg;
}
}
readonly struct были представлены в C# 7.2. Основная идея состоит в том, чтобы сделать структуру неизменяемой. Конечно, вы можете сделать это без модификатора только для чтения (например, DateTime существует с самого начала), но компилятор поможет вам, если вы нарушите логику только для чтения.
Пример выше выдаст несколько ошибок компилятора, если добавить readonly к объявлению структуры. Причина проста: во-первых, мы должны объявить все поля как readonly (иначе любой вызывающий объект мог бы просто изменить их). Во-вторых, метод ShiftToGrayscale по-прежнему изменяет внутреннее состояние, поэтому его тоже надо изменить на выдачу новой структуры:
public readonly struct ColorНеизменяемость дает много преимуществ:
{
public readonly byte Red;
public readonly byte Green;
public readonly byte Blue;
public Color() {
Red = 0; Green = 0; Blue = 0;
}
public Color(byte red, byte green, byte blue)
{
Red = red; Green = green; Blue = blue;
}
public Color ShiftToGrayscale()
{
var avg = (byte)((Red + Green + Blue) / 3);
return new Color (avg, avg, avg);
}
}
- Повышенная тестируемость
- Потокобезопасность.
- Атомарность неудачи.
- Отсутствие скрытых побочных эффектов.
Компилятор попытается помочь вам с неизменяемостью, но не сможет её гарантировать. Если в структуре есть список, его члены всё равно можно будет изменять:
public readonly struct MyStructОкончание следует…
{
public readonly List<int> myStuff
= new List<int>() { 1, 2 };
public MyStruct() {}
public void Mutate()
{
myStuff[0] = 3;
}
}
Источник: https://steven-giesel.com/blogPost/2a52cd8d-b3b2-42e4-87e8-d6dc14147ddb
👍23
День 1716. #ЗаметкиНаПолях
Виды Структур в C#. Окончание
Начало
3. Ref-структура
Также в C# 7.2 Microsoft представили ref-структуру. ref-структуры гарантированно будут жить в стеке и никогда не смогут попасть в кучу. Благодаря этому вы можете реализовать сценарии с низкой аллокацией, в которых не возникает дополнительной нагрузки на сборщика мусора. Компилятор сделает это за вас, он запретит все сценарии, в которых тип значения перемещается в кучу.
Таким образом, ref-структура НЕ может:
- Быть типом элемента массива, полем класса или полем неref-структуры.
Поскольку массивы и классы всегда живут в куче, понятно, что размещать её там в качестве поля запрещено.
- Быть захвачена лямбда-выражением или локальной функцией.
Лямбда-выражение, а также локальные функции находятся за пределами родительской области видимости, и поэтому их необходимо упаковывать.
- Быть использована в асинхронном методе.
Компилятор создаёт конечный автомат для выполнения продолжения (кода после await), которая сама по себе является классом.
- Быть использована в итераторах.
Та же причина, компилятор создаёт конечный автомат, который продляет область действия/время жизни, и поэтому ref-структура окажется в куче.
- Реализовывать интерфейсы (кроме IDisposable).
Использование ref-структур очень ограничено, но всё же они имеют применение. Одним из наиболее ярких примеров является Span<T>.
4. Ref-структура только для чтения
Модификаторы ref и readonly можно объединить. Это будет означать, что структура должна быть неизменяемой и благодаря ключевому слову ref может находиться только в стеке.
5. Структуры-записи
Появились в C# 10. И подобно записям, которые «расширяют» классы, структуры-записи расширяют структуры. Это хороший синтаксический сахар от компилятора, который даёт вам «предопределённые» реализации Equals, ToString() и GetHashcode.
Мы можем легко переопределить нашу структуру Color:
6. Структуры-записи только для чтения
Конечно, вы также можете применить ключевое слово readonly к структуре-записи, оно будет делать то же самое, что и «обычная» структура, то есть компилятор будет налагать определённые ограничения для обеспечения неизменяемости.
7. Ref-структура-запись только для чтения
readonly ref record struct не существует))) Так же, как и ref record struct. Причина очень проста: структура записи реализует IEquatable<T>, а ранее мы видели, что ref-структурам не разрешено реализовывать какой-либо интерфейс, кроме IDisposable.
Источник: https://steven-giesel.com/blogPost/2a52cd8d-b3b2-42e4-87e8-d6dc14147ddb
Виды Структур в C#. Окончание
Начало
3. Ref-структура
Также в C# 7.2 Microsoft представили ref-структуру. ref-структуры гарантированно будут жить в стеке и никогда не смогут попасть в кучу. Благодаря этому вы можете реализовать сценарии с низкой аллокацией, в которых не возникает дополнительной нагрузки на сборщика мусора. Компилятор сделает это за вас, он запретит все сценарии, в которых тип значения перемещается в кучу.
Таким образом, ref-структура НЕ может:
- Быть типом элемента массива, полем класса или полем неref-структуры.
Поскольку массивы и классы всегда живут в куче, понятно, что размещать её там в качестве поля запрещено.
- Быть захвачена лямбда-выражением или локальной функцией.
Лямбда-выражение, а также локальные функции находятся за пределами родительской области видимости, и поэтому их необходимо упаковывать.
- Быть использована в асинхронном методе.
Компилятор создаёт конечный автомат для выполнения продолжения (кода после await), которая сама по себе является классом.
- Быть использована в итераторах.
Та же причина, компилятор создаёт конечный автомат, который продляет область действия/время жизни, и поэтому ref-структура окажется в куче.
- Реализовывать интерфейсы (кроме IDisposable).
Использование ref-структур очень ограничено, но всё же они имеют применение. Одним из наиболее ярких примеров является Span<T>.
4. Ref-структура только для чтения
Модификаторы ref и readonly можно объединить. Это будет означать, что структура должна быть неизменяемой и благодаря ключевому слову ref может находиться только в стеке.
5. Структуры-записи
Появились в C# 10. И подобно записям, которые «расширяют» классы, структуры-записи расширяют структуры. Это хороший синтаксический сахар от компилятора, который даёт вам «предопределённые» реализации Equals, ToString() и GetHashcode.
Мы можем легко переопределить нашу структуру Color:
public record struct Color(Все остальные методы компилятор сгенерирует за вас. Важно, что записи автоматически реализуют IEquatable<T>. Полную реализацию можно посмотреть на Sharplab.io.
byte Red, byte Green, byte Blue)
{
public Color ShiftToGrayscale()
{
var avg = (byte)((Red + Green + Blue) / 3);
return new Color (avg, avg, avg);
}
}
6. Структуры-записи только для чтения
Конечно, вы также можете применить ключевое слово readonly к структуре-записи, оно будет делать то же самое, что и «обычная» структура, то есть компилятор будет налагать определённые ограничения для обеспечения неизменяемости.
7. Ref-структура-запись только для чтения
readonly ref record struct не существует))) Так же, как и ref record struct. Причина очень проста: структура записи реализует IEquatable<T>, а ранее мы видели, что ref-структурам не разрешено реализовывать какой-либо интерфейс, кроме IDisposable.
Источник: https://steven-giesel.com/blogPost/2a52cd8d-b3b2-42e4-87e8-d6dc14147ddb
👍18
День 1717. #ЧтоНовенького
C# Dev Kit для VS Code Теперь Общедоступен
Microsoft представили расширение C# Dev Kit для Visual Studio Code ещё в июне. Оно призвано обеспечить улучшенный опыт разработки на C# для Linux, macOS и Windows. В расширении используется технология с открытым исходным кодом, обеспечивающая гибкую и эффективную среду программирования для разработчиков .NET.
В прошлом месяце Microsoft объявили о прекращении поддержки Visual Studio для Mac. Это решение связано с тем, что они переключили своё внимание на оптимизацию Visual Studio и ориентацию VS Code для кроссплатформенной разработки. Поэтому на прошлой неделе Microsoft объявили, что C# Dev Kit станет общедоступным для всех. Хотя расширение общедоступно, важно отметить, что поддержка .NET MAUI и Unity всё ещё находится в предварительной версии.
Что касается будущего C# Dev Kit, в Microsoft намерены работать над ним на основе отзывов пользователей и постоянно улучшать его производительность, надёжность и набор функций для лучшей поддержки разработки C# в VS Code. Кроме того, пользователи могут ожидать ежемесячных обновлений расширения.
Для разработчиков, которые хотят получить представление о предстоящих функциях и исправлениях, есть возможность выбрать превью-канал. Там Microsoft предоставит ранний доступ к новым функциям и решениям, находящимся на стадии разработки продукта. Кроме того, Microsoft призывает сообщество активно участвовать и делиться своими отзывами.
Объявление о выходе C# Dev Kit получило приличное количество комментариев сообщества Reddit. Например, пользователь SupaMook написал:
«Я пользователь Windows, какое-то время использовал VS2022, но сейчас практически полностью перешел на VSCode. Я думаю, что он прекрасно работает, и мне нравится, что я могу работать с одной IDE или, точнее, с редактором.
Единственное, что меня беспокоит, так это то, что работать на двух мониторах не так удобно. В отличие от VS, где вы можете просто перетащить файл на другой экран, в VSCode вам нужно заново открыть тот же workspace или что-то в этом роде (я не очень понял эту концепцию, но это единственный минус для меня)»
В комментариях также несколько раз обсуждалось лицензирование расширения, поэтому важно отметить, что C# Dev Kit согласует свой подход к лицензированию с Visual Studio. Это означает, что он бесплатен для частных лиц, академических пользователей и разработчиков открытого исходного кода на тех же условиях, что и версия Visual Studio для сообщества.
Для организаций C# Dev Kit поставляется в комплекте с подписками Visual Studio Professional и Enterprise, а также с GitHub Codespaces, что делает его доступным для широкого круга пользователей с различными потребностями.
Скотт Хансельман, вице-президент сообщества разработчиков Microsoft, опубликовал на YouTube очень познавательное видео. Там он продемонстрировал множество функций, таких как Solution Explorer, IntelliSense, отладка, лицензирование, а также общее описание расширения C# Dev Kit.
Также вчера прошёл стрим Visual Studio Toolbox о работе в C# Dev Kit.
Источник: https://www.infoq.com/news/2023/10/csharp-dev-kit-ga/
C# Dev Kit для VS Code Теперь Общедоступен
Microsoft представили расширение C# Dev Kit для Visual Studio Code ещё в июне. Оно призвано обеспечить улучшенный опыт разработки на C# для Linux, macOS и Windows. В расширении используется технология с открытым исходным кодом, обеспечивающая гибкую и эффективную среду программирования для разработчиков .NET.
В прошлом месяце Microsoft объявили о прекращении поддержки Visual Studio для Mac. Это решение связано с тем, что они переключили своё внимание на оптимизацию Visual Studio и ориентацию VS Code для кроссплатформенной разработки. Поэтому на прошлой неделе Microsoft объявили, что C# Dev Kit станет общедоступным для всех. Хотя расширение общедоступно, важно отметить, что поддержка .NET MAUI и Unity всё ещё находится в предварительной версии.
Что касается будущего C# Dev Kit, в Microsoft намерены работать над ним на основе отзывов пользователей и постоянно улучшать его производительность, надёжность и набор функций для лучшей поддержки разработки C# в VS Code. Кроме того, пользователи могут ожидать ежемесячных обновлений расширения.
Для разработчиков, которые хотят получить представление о предстоящих функциях и исправлениях, есть возможность выбрать превью-канал. Там Microsoft предоставит ранний доступ к новым функциям и решениям, находящимся на стадии разработки продукта. Кроме того, Microsoft призывает сообщество активно участвовать и делиться своими отзывами.
Объявление о выходе C# Dev Kit получило приличное количество комментариев сообщества Reddit. Например, пользователь SupaMook написал:
«Я пользователь Windows, какое-то время использовал VS2022, но сейчас практически полностью перешел на VSCode. Я думаю, что он прекрасно работает, и мне нравится, что я могу работать с одной IDE или, точнее, с редактором.
Единственное, что меня беспокоит, так это то, что работать на двух мониторах не так удобно. В отличие от VS, где вы можете просто перетащить файл на другой экран, в VSCode вам нужно заново открыть тот же workspace или что-то в этом роде (я не очень понял эту концепцию, но это единственный минус для меня)»
В комментариях также несколько раз обсуждалось лицензирование расширения, поэтому важно отметить, что C# Dev Kit согласует свой подход к лицензированию с Visual Studio. Это означает, что он бесплатен для частных лиц, академических пользователей и разработчиков открытого исходного кода на тех же условиях, что и версия Visual Studio для сообщества.
Для организаций C# Dev Kit поставляется в комплекте с подписками Visual Studio Professional и Enterprise, а также с GitHub Codespaces, что делает его доступным для широкого круга пользователей с различными потребностями.
Скотт Хансельман, вице-президент сообщества разработчиков Microsoft, опубликовал на YouTube очень познавательное видео. Там он продемонстрировал множество функций, таких как Solution Explorer, IntelliSense, отладка, лицензирование, а также общее описание расширения C# Dev Kit.
Также вчера прошёл стрим Visual Studio Toolbox о работе в C# Dev Kit.
Источник: https://www.infoq.com/news/2023/10/csharp-dev-kit-ga/
👍18👎1
День 1719. #ВопросыНаСобеседовании #Многопоточность
Самые часто задаваемые вопросы на собеседовании по C#
25. Как реализовать синхронизацию потоков с помощью ReaderWriterLockSlim? В чём его преимущества перед традиционным ReaderWriterLock?
ReaderWriterLockSlim — это примитив синхронизации, обеспечивающий эффективный доступ для чтения и записи к общим ресурсам. Он позволяет несколько одновременных чтений, когда ни один писатель не удерживает блокировку и эксклюзивный доступ для записи.
Чтобы добиться синхронизации потоков с помощью ReaderWriterLockSlim, нужно:
1) Создать экземпляр ReaderWriterLockSlim.
2) Использовать EnterReadLock() перед доступом к общему ресурсу для чтения и ExitReadLock() после завершения операции чтения.
3) Использовать EnterWriteLock() перед доступом к общему ресурсу для записи и ExitWriteLock() после завершения операции записи.
1) Производительность: ReaderWriterLockSlim использует относительно дешёвую спин-блокировку и другие оптимизации для сценариев, в которых ожидается, что блокировка будет беспрепятственной или будет удерживаться в течение короткого времени.
2) Рекурсия: ReaderWriterLockSlim обеспечивает гибкую поддержку рекурсии блокировки, позволяя вам несколько раз входить и выходить из блокировки в одном потоке, тогда как ReaderWriterLock имеет ограничения на рекурсию.
3) Предотвращение нехватки писателей (writer starvation): ReaderWriterLockSlim имеет возможности уменьшить нехватку писателей, отдавая предпочтение запросам на блокировку записи вместо запросов на чтение. ReaderWriterLock может страдать от нехватки писателей при наличии непрерывного потока читателей.
Однако обратите внимание, что ReaderWriterLockSlim не поддерживает межпроцессную синхронизацию, и его не следует использовать, если объект блокировки необходимо использовать в нескольких процессах. В таких случаях используйте примитив синхронизации Mutex.
Источник: https://dev.to/bytehide/c-multithreading-interview-questions-and-answers-4opj
Самые часто задаваемые вопросы на собеседовании по C#
25. Как реализовать синхронизацию потоков с помощью ReaderWriterLockSlim? В чём его преимущества перед традиционным ReaderWriterLock?
ReaderWriterLockSlim — это примитив синхронизации, обеспечивающий эффективный доступ для чтения и записи к общим ресурсам. Он позволяет несколько одновременных чтений, когда ни один писатель не удерживает блокировку и эксклюзивный доступ для записи.
Чтобы добиться синхронизации потоков с помощью ReaderWriterLockSlim, нужно:
1) Создать экземпляр ReaderWriterLockSlim.
2) Использовать EnterReadLock() перед доступом к общему ресурсу для чтения и ExitReadLock() после завершения операции чтения.
3) Использовать EnterWriteLock() перед доступом к общему ресурсу для записи и ExitWriteLock() после завершения операции записи.
var rwl = new ReaderWriterLockSlim();Преимущества ReaderWriterLockSlim над ReaderWriterLock:
// чтение
rwl.EnterReadLock();
try
{
// Доступ к общему ресурсу для чтения
}
finally
{
rwl.ExitReadLock();
}
// Запись
rwl.EnterWriteLock();
try
{
// Доступ к общему ресурсу для записи
}
finally
{
rwl.ExitWriteLock();
}
1) Производительность: ReaderWriterLockSlim использует относительно дешёвую спин-блокировку и другие оптимизации для сценариев, в которых ожидается, что блокировка будет беспрепятственной или будет удерживаться в течение короткого времени.
2) Рекурсия: ReaderWriterLockSlim обеспечивает гибкую поддержку рекурсии блокировки, позволяя вам несколько раз входить и выходить из блокировки в одном потоке, тогда как ReaderWriterLock имеет ограничения на рекурсию.
3) Предотвращение нехватки писателей (writer starvation): ReaderWriterLockSlim имеет возможности уменьшить нехватку писателей, отдавая предпочтение запросам на блокировку записи вместо запросов на чтение. ReaderWriterLock может страдать от нехватки писателей при наличии непрерывного потока читателей.
Однако обратите внимание, что ReaderWriterLockSlim не поддерживает межпроцессную синхронизацию, и его не следует использовать, если объект блокировки необходимо использовать в нескольких процессах. В таких случаях используйте примитив синхронизации Mutex.
Источник: https://dev.to/bytehide/c-multithreading-interview-questions-and-answers-4opj
👍10
Код на картинке в первом комментарии...
Anonymous Quiz
19%
не скомпилируется
28%
будет всегда выдавать ошибку во время выполнения
22%
выполнится без ошибок
31%
будет выдавать ошибку от случая к случаю
👍5