День 2382. #ЗаметкиНаПолях
Алгоритмы Выбора Главного Узла в Распределённых БД. Продолжение
1. Алгоритм Забияки
2. Кольцевой Алгоритм
3. Алгоритм Paxos
4. Алгоритм Raft
Raft существует, потому что Paxos, несмотря на свою мощь, сложен в реализации и ещё сложнее в понимании. Raft предоставляет те же гарантии безопасности, что и Paxos, например, отсутствие двух лидеров одновременно, согласование журнала и отслеживание прогресса при наличии кворума. Однако архитектуру проще отслеживать, отлаживать и развёртывать.
Каждый узел Raft находится в одном из трёх состояний:
- Ведомый (Follower) - пассивный узел, слушает лидера и отвечает на запросы.
- Кандидат (Candidate) - пытается стать лидером при отсутствии тактовых импульсов.
- Лидер (Leader) - активный узел, который обрабатывает все клиентские запросы и репликацию.
Узлы начинают работу как ведомые. Если они слишком долго не получают ответ от лидера (по тактовым импульсам), они считают лидера мёртвым и запускают выборы (см. диаграмму ниже).
Raft предотвращает конфликты выборов, используя рандомизированные таймауты. Каждый ведомый начинает обратный отсчёт со случайным значением, например, от 150 до 300 миллисекунд. Если до истечения таймера он не получает ответа от лидера, он становится кандидатом и начинает выборы.
Кандидат:
- Увеличивает свой срок полномочий (своего рода счётчик эпох).
- Голосует за себя.
- Отправляет RPC-запросы «RequestVote» всем остальным узлам.
- Другие узлы будут голосовать за кандидата только в том случае, если:
они не голосовали в текущем сроке полномочий и журнал кандидата как минимум не менее актуален, чем их собственный.
- Если кандидат получает голоса большинства, он становится новым лидером и начинает отправлять тактовые импульсы для поддержания своего статуса. Если ни один из кандидатов не побеждает (например, голоса разделились), все ждут и повторяют попытки с новыми таймаутами. Такой рандомизированный подход гарантирует, что один из узлов в итоге опередит остальных.
Raft использует сроки полномочий (term) для отслеживания эпох лидерства. Каждая запись в журнале привязана к сроку полномочий, в котором она была создана. Это позволяет легко обнаруживать и отклонять устаревших или конфликтующих лидеров. Перед голосованием узлы сравнивают журналы. Кандидат с устаревшим журналом будет отклонён, даже если его запрос первым достигнет других узлов. Это гарантирует, что лидером может стать только узел с самой актуальной версией журнала. Затем лидеры реплицируют новые записи журнала на ведомых с помощью RPC-вызовов «AppendEntries». После того, как кворум подтвердил запись, она считается подтверждённой.
Raft решает проблему разделения власти, применяя правила кворума:
- Лидер должен иметь поддержку большинства узлов.
- Два лидера не могут быть активны в одном и том же сроке.
- Ведомый принимает запросы только от лидера текущего срока.
- Если устаревший лидер пытается действовать после разделения сети, он немедленно отклоняется ведомыми с более новым сроком.
Эта чёткая структура позволяет избежать неоднозначности, характерной для таких протоколов, как базовый Paxos, где одновременное выдвижение предложений может замедлять работу узлов или приводить системы в состояние неопределённости.
Окончание следует…
Источник: https://blog.bytebytego.com/p/top-leader-election-algorithms-in
Алгоритмы Выбора Главного Узла в Распределённых БД. Продолжение
1. Алгоритм Забияки
2. Кольцевой Алгоритм
3. Алгоритм Paxos
4. Алгоритм Raft
Raft существует, потому что Paxos, несмотря на свою мощь, сложен в реализации и ещё сложнее в понимании. Raft предоставляет те же гарантии безопасности, что и Paxos, например, отсутствие двух лидеров одновременно, согласование журнала и отслеживание прогресса при наличии кворума. Однако архитектуру проще отслеживать, отлаживать и развёртывать.
Каждый узел Raft находится в одном из трёх состояний:
- Ведомый (Follower) - пассивный узел, слушает лидера и отвечает на запросы.
- Кандидат (Candidate) - пытается стать лидером при отсутствии тактовых импульсов.
- Лидер (Leader) - активный узел, который обрабатывает все клиентские запросы и репликацию.
Узлы начинают работу как ведомые. Если они слишком долго не получают ответ от лидера (по тактовым импульсам), они считают лидера мёртвым и запускают выборы (см. диаграмму ниже).
Raft предотвращает конфликты выборов, используя рандомизированные таймауты. Каждый ведомый начинает обратный отсчёт со случайным значением, например, от 150 до 300 миллисекунд. Если до истечения таймера он не получает ответа от лидера, он становится кандидатом и начинает выборы.
Кандидат:
- Увеличивает свой срок полномочий (своего рода счётчик эпох).
- Голосует за себя.
- Отправляет RPC-запросы «RequestVote» всем остальным узлам.
- Другие узлы будут голосовать за кандидата только в том случае, если:
они не голосовали в текущем сроке полномочий и журнал кандидата как минимум не менее актуален, чем их собственный.
- Если кандидат получает голоса большинства, он становится новым лидером и начинает отправлять тактовые импульсы для поддержания своего статуса. Если ни один из кандидатов не побеждает (например, голоса разделились), все ждут и повторяют попытки с новыми таймаутами. Такой рандомизированный подход гарантирует, что один из узлов в итоге опередит остальных.
Raft использует сроки полномочий (term) для отслеживания эпох лидерства. Каждая запись в журнале привязана к сроку полномочий, в котором она была создана. Это позволяет легко обнаруживать и отклонять устаревших или конфликтующих лидеров. Перед голосованием узлы сравнивают журналы. Кандидат с устаревшим журналом будет отклонён, даже если его запрос первым достигнет других узлов. Это гарантирует, что лидером может стать только узел с самой актуальной версией журнала. Затем лидеры реплицируют новые записи журнала на ведомых с помощью RPC-вызовов «AppendEntries». После того, как кворум подтвердил запись, она считается подтверждённой.
Raft решает проблему разделения власти, применяя правила кворума:
- Лидер должен иметь поддержку большинства узлов.
- Два лидера не могут быть активны в одном и том же сроке.
- Ведомый принимает запросы только от лидера текущего срока.
- Если устаревший лидер пытается действовать после разделения сети, он немедленно отклоняется ведомыми с более новым сроком.
Эта чёткая структура позволяет избежать неоднозначности, характерной для таких протоколов, как базовый Paxos, где одновременное выдвижение предложений может замедлять работу узлов или приводить системы в состояние неопределённости.
Окончание следует…
Источник: https://blog.bytebytego.com/p/top-leader-election-algorithms-in
👍2
День 2383. #ЗаметкиНаПолях
Алгоритмы Выбора Главного Узла в Распределённых БД. Окончание
1. Алгоритм Забияки
2. Кольцевой Алгоритм
3. Алгоритм Paxos
4. Алгоритм Raft
5. Zookeeper и Zab
ZooKeeper не является БД. Он не хранит записи пользователей, индексы запросов и не реплицирует записи журнала. Вместо этого он играет важнейшую роль в распределённой экосистеме: координирует работу. Когда системам требуется выбрать брокера, управлять отказоустойчивостью лидера или синхронизировать конфигурацию, ZooKeeper — незаменимый сервис.
Внутренне ZooKeeper использует протокол Zab (ZooKeeper Atomic Broadcast). Zab обрабатывает как выбор лидера, так и репликацию состояния, гарантируя безопасность, согласованность и отказоустойчивость даже метаданных координации (см. диаграмму ниже).
Zab обеспечивает надёжность выборов лидера в ZooKeeper. Прежде чем новый лидер сможет начать обработку запросов на запись, он должен синхронизироваться с кворумом ведомых, чтобы убедиться, что у него самое последнее зафиксированное состояние.
Каждая транзакция в ZooKeeper помечается zxid (идентификатором транзакции ZooKeeper), который объединяет эпоху лидера и индекс журнала. Это позволяет узлам определять, кто имеет наиболее актуальную картину мира.
Во время выборов лидера в Zab:
- Предпочтение отдаётся кандидату с наиболее актуальным ZXID.
- Новый лидер должен пройти фазу синхронизации состояния с кворумом, прежде чем сможет фиксировать новые транзакции.
- Если синхронизация не удаётся, выборы завершаются неудачей, и повторяются.
Итого
Каждый алгоритм выборов лидера решает одну и ту же фундаментальную задачу: выбор одного надёжного лидера в распределённой системе. Но они подходят к этому с разными допущениями, компромиссами и эксплуатационными характеристиками.
- Алгоритмы Забияки и Кольцевой используют детерминированные правила, основанные на идентификаторах узлов. Paxos, Raft и Zab используют принятие решений на основе кворума.
- Для обеспечения отказоустойчивости алгоритм Забияки предполагает надёжные соединения и точное обнаружение сбоев. Узел, ложно помеченный как мёртвый, может привести к появлению нескольких лидеров или частым перевыборам. Кольцевой алгоритм останавливается, если любой узел в кольце выходит из строя без предупреждения. В отличие от этого, Paxos, Raft и Zab допускают частичные сбои и продолжают принимать безопасные решения.
- С точки зрения производительности, Raft и ZooKeeper/Zab предсказуемо справляются с перевыборами. Алгоритмы Забияки и Кольцевой неэффективны в средах с высокой текучестью. Paxos, особенно в базовой версии, может испытывать трудности при наличии нескольких предлагающих узлов и нечётком лидерстве, если не использовать такие усовершенствования, как Multi-Paxos.
- Алгоритмы Забияки и Кольцевой просты в реализации. Raft требует больше усилий. Paxos довольно сложно настроить правильно. ZooKeeper/Zab скрывает сложность за API, но лежащие в его основе механизмы нетривиальны.
Источник: https://blog.bytebytego.com/p/top-leader-election-algorithms-in
Алгоритмы Выбора Главного Узла в Распределённых БД. Окончание
1. Алгоритм Забияки
2. Кольцевой Алгоритм
3. Алгоритм Paxos
4. Алгоритм Raft
5. Zookeeper и Zab
ZooKeeper не является БД. Он не хранит записи пользователей, индексы запросов и не реплицирует записи журнала. Вместо этого он играет важнейшую роль в распределённой экосистеме: координирует работу. Когда системам требуется выбрать брокера, управлять отказоустойчивостью лидера или синхронизировать конфигурацию, ZooKeeper — незаменимый сервис.
Внутренне ZooKeeper использует протокол Zab (ZooKeeper Atomic Broadcast). Zab обрабатывает как выбор лидера, так и репликацию состояния, гарантируя безопасность, согласованность и отказоустойчивость даже метаданных координации (см. диаграмму ниже).
Zab обеспечивает надёжность выборов лидера в ZooKeeper. Прежде чем новый лидер сможет начать обработку запросов на запись, он должен синхронизироваться с кворумом ведомых, чтобы убедиться, что у него самое последнее зафиксированное состояние.
Каждая транзакция в ZooKeeper помечается zxid (идентификатором транзакции ZooKeeper), который объединяет эпоху лидера и индекс журнала. Это позволяет узлам определять, кто имеет наиболее актуальную картину мира.
Во время выборов лидера в Zab:
- Предпочтение отдаётся кандидату с наиболее актуальным ZXID.
- Новый лидер должен пройти фазу синхронизации состояния с кворумом, прежде чем сможет фиксировать новые транзакции.
- Если синхронизация не удаётся, выборы завершаются неудачей, и повторяются.
Итого
Каждый алгоритм выборов лидера решает одну и ту же фундаментальную задачу: выбор одного надёжного лидера в распределённой системе. Но они подходят к этому с разными допущениями, компромиссами и эксплуатационными характеристиками.
- Алгоритмы Забияки и Кольцевой используют детерминированные правила, основанные на идентификаторах узлов. Paxos, Raft и Zab используют принятие решений на основе кворума.
- Для обеспечения отказоустойчивости алгоритм Забияки предполагает надёжные соединения и точное обнаружение сбоев. Узел, ложно помеченный как мёртвый, может привести к появлению нескольких лидеров или частым перевыборам. Кольцевой алгоритм останавливается, если любой узел в кольце выходит из строя без предупреждения. В отличие от этого, Paxos, Raft и Zab допускают частичные сбои и продолжают принимать безопасные решения.
- С точки зрения производительности, Raft и ZooKeeper/Zab предсказуемо справляются с перевыборами. Алгоритмы Забияки и Кольцевой неэффективны в средах с высокой текучестью. Paxos, особенно в базовой версии, может испытывать трудности при наличии нескольких предлагающих узлов и нечётком лидерстве, если не использовать такие усовершенствования, как Multi-Paxos.
- Алгоритмы Забияки и Кольцевой просты в реализации. Raft требует больше усилий. Paxos довольно сложно настроить правильно. ZooKeeper/Zab скрывает сложность за API, но лежащие в его основе механизмы нетривиальны.
Источник: https://blog.bytebytego.com/p/top-leader-election-algorithms-in
👍4
День 2384. #TipsAndTricks
Как Продолжить Выполнение Процесса После Завершения Задания GitHub Action
После завершения задания GitHub Actions обработчик завершает все запущенные им дочерние процессы. Он идентифицирует эти процессы, проверяя переменную окружения RUNNER_TRACKING_ID. Любой процесс, где эта переменная установлена переменной считается дочерним процессом обработчика и будет остановлен.
Чтобы процесс продолжил работу после завершения задания, запустите его без переменной окружения RUNNER_TRACKING_ID:
Либо:
Примечание: В обработчиках, размещенных на GitHub, это решение не поможет, поскольку вся виртуальная машина удаляется после завершения задания.
Источник: https://www.meziantou.net/how-to-keep-processes-running-after-a-github-action-job-ends.htm
Как Продолжить Выполнение Процесса После Завершения Задания GitHub Action
После завершения задания GitHub Actions обработчик завершает все запущенные им дочерние процессы. Он идентифицирует эти процессы, проверяя переменную окружения RUNNER_TRACKING_ID. Любой процесс, где эта переменная установлена переменной считается дочерним процессом обработчика и будет остановлен.
Чтобы процесс продолжил работу после завершения задания, запустите его без переменной окружения RUNNER_TRACKING_ID:
var psi = new ProcessStartInfo("sample_app");
psi.EnvironmentVariables.Remove("RUNNER_TRACKING_ID");
Process.Start(psi);
Либо:
# Вариант 1
$env:RUNNER_TRACKING_ID = $null
# Вариант 2
$psi = New-Object System.Diagnostics.ProcessStartInfo "sample_app"
$psi.EnvironmentVariables.Remove("RUNNER_TRACKING_ID")
[System.Diagnostics.Process]::Start($psi)
Примечание: В обработчиках, размещенных на GitHub, это решение не поможет, поскольку вся виртуальная машина удаляется после завершения задания.
Источник: https://www.meziantou.net/how-to-keep-processes-running-after-a-github-action-job-ends.htm
👍2
День 2385. #TipsAndTricks
5 Современных Возможностей C#, Которые Улучшат Ваш Код
C# стал гораздо более выразительным и мощным языком, чем был ещё несколько лет назад. Вот 5 новинок языка, которые отличают инженеров, просто «знающих C#», от тех, кто использует его на полную.
1. Структуры только для чтения для критически важных для производительности типов-значений
Обычная структура копируется без необходимости, что приводит к скрытым потерям производительности. Отметив её как только для чтения, вы сообщаете компилятору, что её поля никогда не изменятся, что позволяет среде выполнения не создавать защитные копии.
Раньше:
Сейчас:
Для высокопроизводительного кода, такого как графика, игры или API с большим количеством математических вычислений, это небольшое ключевое слово может означать значительную экономию.
2. Ключевое слово scoped для предотвращения использования ref-переменных вне области видимости
C# позволяет использовать ref-переменные для повышения производительности, но распространённой ошибкой является случайное их использование вне области видимости (возвращение ссылки на что-то, что больше не является безопасным). scoped гарантирует во время компиляции, что ссылка не проживёт дольше положенного.
Без scoped:
scoped:
3. Обязательные свойства для принудительной инициализации объекта
Сколько раз вы создавали объект и забывали установить одно из его критически важных свойств? При использовании обязательных свойств компилятор принуждает инициализировать объект.
Раньше:
Сейчас:
4. Возврат типа ref readonly, чтобы избежать защитного копирования
При возврате больших структур возврат по значению часто приводит к ненужному копированию. Возврат типа ref readonly даёт вызывающим функциям ссылку на объект, который они могут читать, но не могут изменять.
Без ref readonly:
С ref readonly:
Это особенно актуально в библиотеках, критичных к производительности, где структуры неизменяемы, но копирование требует больших затрат.
5. Статические абстрактные члены в интерфейсах для обобщённой математики
Это кажется узкоспециализированной функцией, но открывает доступ к настоящей обобщённой математике без рефлексии и упаковки. До появления этой функции нельзя было писать обобщённые алгоритмы, работающие с числовыми типами:
Благодаря статическим абстрактным членам, INumber<T> определяет операторы и константы обобщённо, обеспечивая чистые, независимые от типов математические библиотеки.
Итого
Современный C# — это не просто новый синтаксис; это достижение ясности, безопасности и производительности, которых просто не могли предложить старые версии. Начните внедрять эти функции в свой код, и вы не только начнёте писать лучшее ПО, но и по-новому взглянете на возможности языка.
Источник: https://blog.stackademic.com/5-modern-c-features-that-will-make-your-code-feel-like-magic-d1ef6a374d13
5 Современных Возможностей C#, Которые Улучшат Ваш Код
C# стал гораздо более выразительным и мощным языком, чем был ещё несколько лет назад. Вот 5 новинок языка, которые отличают инженеров, просто «знающих C#», от тех, кто использует его на полную.
1. Структуры только для чтения для критически важных для производительности типов-значений
Обычная структура копируется без необходимости, что приводит к скрытым потерям производительности. Отметив её как только для чтения, вы сообщаете компилятору, что её поля никогда не изменятся, что позволяет среде выполнения не создавать защитные копии.
Раньше:
public struct Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y) => (X, Y) = (x, y);
}
Сейчас:
public readonly struct Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y) => (X, Y) = (x, y);
}
Для высокопроизводительного кода, такого как графика, игры или API с большим количеством математических вычислений, это небольшое ключевое слово может означать значительную экономию.
2. Ключевое слово scoped для предотвращения использования ref-переменных вне области видимости
C# позволяет использовать ref-переменные для повышения производительности, но распространённой ошибкой является случайное их использование вне области видимости (возвращение ссылки на что-то, что больше не является безопасным). scoped гарантирует во время компиляции, что ссылка не проживёт дольше положенного.
Без scoped:
ref int Dangerous(ref int number)
{
// Может быть использовано извне и привести к проблемам
return ref number;
}
scoped:
ref int Safe(scoped ref int number)
{
// Компилятор проверяет, что number может
// использоваться только внутри метода
// и выдаёт ошибку компиляции
return ref number;
}
3. Обязательные свойства для принудительной инициализации объекта
Сколько раз вы создавали объект и забывали установить одно из его критически важных свойств? При использовании обязательных свойств компилятор принуждает инициализировать объект.
Раньше:
public class User
{
public string Name { get; set; }
public string Email { get; set; }
}
// Можно забыть инициализировать свойства
var user = new User { Name = "John" };
Сейчас:
public class User
{
public required string Name { get; init; }
public required string Email { get; init; }
}
// Компилятор проверяет полноту инициализации
var user = new User {
Name = "John", Email = "[email protected]" };
4. Возврат типа ref readonly, чтобы избежать защитного копирования
При возврате больших структур возврат по значению часто приводит к ненужному копированию. Возврат типа ref readonly даёт вызывающим функциям ссылку на объект, который они могут читать, но не могут изменять.
Без ref readonly:
public BigStruct GetData() =>
_bigStruct; // Копирует структуру
С ref readonly:
public ref readonly BigStruct GetData() =>
ref _bigStruct; // Нет копирования
Это особенно актуально в библиотеках, критичных к производительности, где структуры неизменяемы, но копирование требует больших затрат.
5. Статические абстрактные члены в интерфейсах для обобщённой математики
Это кажется узкоспециализированной функцией, но открывает доступ к настоящей обобщённой математике без рефлексии и упаковки. До появления этой функции нельзя было писать обобщённые алгоритмы, работающие с числовыми типами:
T Add<T>(T a, T b) where T : INumber<T>
=> a + b;
Благодаря статическим абстрактным членам, INumber<T> определяет операторы и константы обобщённо, обеспечивая чистые, независимые от типов математические библиотеки.
Итого
Современный C# — это не просто новый синтаксис; это достижение ясности, безопасности и производительности, которых просто не могли предложить старые версии. Начните внедрять эти функции в свой код, и вы не только начнёте писать лучшее ПО, но и по-новому взглянете на возможности языка.
Источник: https://blog.stackademic.com/5-modern-c-features-that-will-make-your-code-feel-like-magic-d1ef6a374d13
👍26
День 2386. #ЗаметкиНаПолях
Неожиданная Несогласованность в Записях
На днях Джон Скит пытался найти ошибку в своём коде, и она оказалась следствием его непонимания принципов работы записей в C#. Как показывает вчерашний опрос, он не единственный, кто ожидал, что они будут работать именно так.
Когда записи появились в C#, одновременно появился и оператор «обратимого изменения» with. Идея заключается в том, что типы записей неизменяемы, но вы можете легко и эффективно создать новый экземпляр с теми же данными, что и существующий экземпляр, но с другими значениями некоторых свойств:
Это не изменяет данные первоначальной записи, т.е. entry.Score останется 5000.
Проблема
В качестве очень простого (и весьма надуманного) примера можно создать запись, которая определяет, является ли значение чётным или нечётным при инициализации:
На первый взгляд, всё нормально:
Но если мы изменим код на использование with:
Джон (и не только он) всегда предполагал, что оператор with вызывает конструктор с новыми значениями. На самом деле это не так. Оператор with выше преобразуется в примерно такой код:
Метод <Clone>$ (по крайней мере, в этом случае) вызывает сгенерированный конструктор копирования (Number(Number)), который копирует как Value, так и резервное поле для Even (т.е. значение Even). Всё это документировано, но пока компилятор не выдаёт никаких предупреждений о возможных несоответствиях, которые это может вызвать.
Конечно, вычисляемое свойство работает правильно. Значение вычисляется каждый раз при обращении к нему:
Что делать?
Пока просто знать об этом и жить дальше. Легко сказать, что можно просто использовать вычисляемые свойства. Проблема, если кто-то, не знающий об этом, добавит/изменит свойство на вычисляемое при инициализации. Либо если запись предоставлена в какой-то внешней библиотеке (не заглядывая в исходный код библиотеки, нет возможности определить какое свойство там использовано). Сложно представить, что это поведение будет изменено в языке. Но Джон попросил Майкрософт хотя бы добавить предупреждение в таких случаях, а также написал собственный анализатор.
Источник: https://codeblog.jonskeet.uk/2025/07/19/unexpected-inconsistency-in-records/
Неожиданная Несогласованность в Записях
На днях Джон Скит пытался найти ошибку в своём коде, и она оказалась следствием его непонимания принципов работы записей в C#. Как показывает вчерашний опрос, он не единственный, кто ожидал, что они будут работать именно так.
Когда записи появились в C#, одновременно появился и оператор «обратимого изменения» with. Идея заключается в том, что типы записей неизменяемы, но вы можете легко и эффективно создать новый экземпляр с теми же данными, что и существующий экземпляр, но с другими значениями некоторых свойств:
public record HighScoreEntry(
string PlayerName, int Score, int Level);
HighScoreEntry entry = new("Jon", 5000, 50);
var updatedEntry =
entry with { Score = 6000, Level = 55 };
Это не изменяет данные первоначальной записи, т.е. entry.Score останется 5000.
Проблема
В качестве очень простого (и весьма надуманного) примера можно создать запись, которая определяет, является ли значение чётным или нечётным при инициализации:
public record Number(int Value)
{
public bool Even { get; } =
(Value & 1) == 0;
}
На первый взгляд, всё нормально:
var n2 = new Number(2);
var n3 = new Number(3);
Console.WriteLine(n2);
// Number { Value = 2, Even = True }
Console.WriteLine(n3);
// Number { Value = 3, Even = False }
Но если мы изменим код на использование with:
var n3 = n2 with { Value = 3 };
Console.WriteLine(n3);
// Number { Value = 3, Even = True }
Джон (и не только он) всегда предполагал, что оператор with вызывает конструктор с новыми значениями. На самом деле это не так. Оператор with выше преобразуется в примерно такой код:
var n3 = n2.<Clone>$();
n3.Value = 3;
Метод <Clone>$ (по крайней мере, в этом случае) вызывает сгенерированный конструктор копирования (Number(Number)), который копирует как Value, так и резервное поле для Even (т.е. значение Even). Всё это документировано, но пока компилятор не выдаёт никаких предупреждений о возможных несоответствиях, которые это может вызвать.
Конечно, вычисляемое свойство работает правильно. Значение вычисляется каждый раз при обращении к нему:
public record Number(int Value)
{
public bool Even => (Value & 1) == 0;
}
Что делать?
Пока просто знать об этом и жить дальше. Легко сказать, что можно просто использовать вычисляемые свойства. Проблема, если кто-то, не знающий об этом, добавит/изменит свойство на вычисляемое при инициализации. Либо если запись предоставлена в какой-то внешней библиотеке (не заглядывая в исходный код библиотеки, нет возможности определить какое свойство там использовано). Сложно представить, что это поведение будет изменено в языке. Но Джон попросил Майкрософт хотя бы добавить предупреждение в таких случаях, а также написал собственный анализатор.
Источник: https://codeblog.jonskeet.uk/2025/07/19/unexpected-inconsistency-in-records/
👍28
День 2387. #Оффтоп
Давно не рекомендовал вам видео. А тут вчера у Дудя вышло прекрасное интервью с Андреем Дороничевым. Это своего рода сиквел популярного фильма Дудя про Кремниевую долину. Андрей с тех пор ушёл из гугла и создал стартап, где использует ИИ для решения разных больших задач (в данный момент – лекарство от рака). В интервью не только про него самого, но и 100500 "тупых вопросов" про ИИ (что он уже может и сможет в будущем, под угрозой ли наши профессии, будет ли восстание машин и т.п.), а также про личностный рост и про IT сферу вообще.
Мне очень понравилось, поэтому делюсь. Выделите 2 часа 40 минут в своём графике. Это интересно.
https://youtu.be/1SLvIof4-Zw
Давно не рекомендовал вам видео. А тут вчера у Дудя вышло прекрасное интервью с Андреем Дороничевым. Это своего рода сиквел популярного фильма Дудя про Кремниевую долину. Андрей с тех пор ушёл из гугла и создал стартап, где использует ИИ для решения разных больших задач (в данный момент – лекарство от рака). В интервью не только про него самого, но и 100500 "тупых вопросов" про ИИ (что он уже может и сможет в будущем, под угрозой ли наши профессии, будет ли восстание машин и т.п.), а также про личностный рост и про IT сферу вообще.
Мне очень понравилось, поэтому делюсь. Выделите 2 часа 40 минут в своём графике. Это интересно.
https://youtu.be/1SLvIof4-Zw
YouTube
Искусственный интеллект и лекарство от рака / вДудь
Более 1700 компаний уже выбрали Astana Hub для выхода на глобальный рынок — присоединяйтесь:
https://astanahub.com/ru/l/kak-otkryt-it-kompanyiu-v-kazakhstane?utm_source=youtube&utm_medium=vdud&utm_campaign=visa
Программы для фаундеров, digital-кочевников…
https://astanahub.com/ru/l/kak-otkryt-it-kompanyiu-v-kazakhstane?utm_source=youtube&utm_medium=vdud&utm_campaign=visa
Программы для фаундеров, digital-кочевников…
👎19👍14