Pull to refresh
-4
0
Send message
при этом отдыхая душой и мозгом как в санатории

Это аргумент! :) Нужно будет при случае почитать документацию по этому Go. :)

Такая же. И вполне можна ситуация, когда игра в максимальных настройках грузит вычислительный модуль видеокарты на 100%. Но для карт игровой серии технически возможно ограничивать вычислительную производительность при отсутсвии 3D рендеринга. Тогда для майнинга и расчетов придется либо делать симуляцию рендеринга, либо покупать профессиональные карты. Думаю, что единственное, чего такими методами можно добиться — это то, что конкуренты продадут больше видеокарт. :)

В видеокарту можно загрузить некий кусок кода, который будет выполнятся на очень многих ядрах. Код достаточно примитивный, но он может принимать в качестве аргументов большие массивы данных и очень быстро их считать, так как выполняется параллельно на многих ядрах, разбивая входные данные на части. В качестве кода можно загрузить алгоритмы хэширования, а можно скучно считать какие-нибудь трансформации 3D объектов. Разница действительно отсутсвует.


Но, смотри как майнинг грузит видеокарту.
$ nvidia-smi dmon


gpu pwr gtemp mtemp sm mem enc dec mclk pclk
Idx W C C % % % % MHz MHz
0   159    51     -   100   100     0     0  7900   990
0   159    51     -   100   100     0     0  7900  1005
0   159    51     -   100   100     0     0  7900   960
0   159    51     -   100   100     0     0  7900   990
0   159    51     -   100   100     0     0  7900   990

100% нагрузки 24 часа в сутки. Прошивка карты вполне может обнаруживать такие ситуации и понижать частоту памяти или ядер. В принципе, она это уже делает. Например, NVidia RTX 3070 при продолжительной 100% нагрузке переключается с performance mode 4 на 3.

Сделал поле не value типа


    public struct MyStruct
    {
        private string _test1;
    }

Поведение такое же, как в случае с int.


Моя структура проекта (стрелками показаны зависимости):
Главный модуль -> библиотека 1 -> библиотека 2


MyStruct объявлен в "библиотека 2", вызывающий код в "библиотека 1"


Проблема в том, что при схеме
net5.0 -> netstandard2.1 -> netstandard2.1
все компилируется. И CancellationToken без явной инициализации, и оба варианта MyStruct (string и int)


При схеме net5.0 -> net5.0 -> netstandard2.1
CancellationToken не компилируется. MyStruct c с полем типа int не компилируется, замена int на string приводит к успешной компиляции.


Из этого видно, что компилятор по-разному определяет инициализацию value и ref типов для приватных полей. Пусть меня опять заминусят, но мне этот цирк не нужен: я просто пропишу в coding conventions требование обязательной явной инициализации структур.


P.S. Спасибо за статью. Очень интересная тема :)

Получается, что такое поведение структур описано в стандарте, как минимум в драфте версии 6.0
https://github.com/ljw1004/csharpspec/blob/gh-pages/variables.md


In order to determine that each used variable is definitely assigned, the compiler must use a process that is equivalent to the one described in this section.

The compiler processes the body of each function member that has one or more initially unassigned variables. For each initially unassigned variable v, the compiler determines a definite assignment state for v at each of the following points in the function member.

Процесс сложный, в связи с этим наблюдаются забавные расхождения в поведении компилятора, когда компилируются две сборки с CancellationToken под net5.0 и netstandard2.1.

Все, получилось!


  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <LangVersion>9.0</LangVersion>
  </PropertyGroup>

Теперь оба не компилируются


        private void Test2(out CancellationToken token)
        {

        }

        private void Test3(out MyStruct test)
        {

        }

Честно говоря, теперь у меня нет логического объяснения, как все это работает.

Тогда не все так просто и объяснение неправильное. Только что откомпилировал следующий код без проблем.


        public Task StopAsync(CancellationToken cancellationToken)
        {
            CancellationToken test;
            Test(ref test);

            Test2(out CancellationToken test2);

            return Task.CompletedTask;
        }

        private void Test(ref CancellationToken token)
        {

        }

        private void Test2(out CancellationToken token)
        {

        }

$ dotnet --version
5.0.103


Теперь я создаю во внешней сборке


    public struct MyStruct
    {
        private int _test1;
    }

и вызов


Test3(out MyStruct test3);
private void Test3(out MyStruct test)
        {

        }

не компилируется.


  <PropertyGroup>
    <TargetFramework>netstandard2.1</TargetFramework>
    <Nullable>enable</Nullable>

Когда мы работаем с ref и out в метод передается указатель (адрес). Так что с 0 байтов в любом случае мимо. Да, во втором случае имплементацией интерфейса могут быть структуры, классы. А так как объект может поддерживать много интерфейсов, то без явной инициализации не обойтись. Претензии есть к первому варианту, так как при изменении MyStruct смысл что-то спрашивать у программиста внезапно появляется.

Я, возможно, неправильно понимаю слово "закономерность". Но вроде бы это должно означать, что пустая структура инициализируется так же, как и не пустая. Да, пустую структуру было бы неплохо инициализировать. В ином случае посмотрите пример ниже, где в NET 5 структура CancellationToken внезапно начала требовать инициализации. Причина — раньше ее не нужно было явно инициализировать.


Еще раз повторюсь: явная инициализация пустой структуры не мешает, вы ее всегда можете переписать при введении новых полей. Если кода инициализации нет вообще — его нужно будет написать. И в этом разница, когда приходится расширять структуру с 0 полей до N, или с N до N+X.

Нет смысла менять версию C# в проекте, там проблема в библиотечном коде.


Определение в NET 4.8


public struct CancellationToken
    {
        // The backing TokenSource.  
        // if null, it implicitly represents the same thing as new CancellationToken(false).
        // When required, it will be instantiated to reflect this.
        private CancellationTokenSource m_source;
        //!! warning. If more fields are added, the assumptions in CreateLinkedToken may no longer be valid
..................
 }

Теперь в NET 5.0


  public readonly struct CancellationToken
  {
    private readonly 
    #nullable disable
    CancellationTokenSource _source;
.............................
}

readonly структура требует readonly полей, включая приватные. Эти поля мы можем инициализировать только в конструкторе. Определить конструктор по умолчанию мы не имеем возможности, так как это структура. В итоге логика с нулем публичных полей больше не работает — мы приплыли! :)


Воспроизводим поведение CancellationToken из NET 5


        MyStruct test; 
        CheckYourself(ref test);

        public readonly struct MyStruct
        {
            private readonly object _test;

            public MyStruct(object obj)
            {
                _test = obj;
            }
        }

Не компилируется, требует инициализации.

Спасибо. Я только вчера завел тут аккаунт. Не привык еще.

Я за обсуждение технических моментов больше минусов отхватил. Но буду продолжать, пока не надоест. :)

Почему же только два способа? Например, ниже третий и четвертый одновременно. :)


        MyStruct test = new MyStruct(1, 2) {a = 3, b = 4};
        CheckYourself(ref test);

        private struct MyStruct 
        {
            public MyStruct(int ia, int ib)
            {
                a = ia;
                b = ib;
            }
            public int a;
            public int b;
        }

В любом случае мы должны должны инициализировать все поля структуры. Либо через конструктор, либо явно, либо через список инициализации. И понятно, что если нечего инициализировать, то можно считать структуру проинициализированной. Тут я протормозил, спасибо за объяснение. Но все же я остаюсь при своем мнении в плане того, что это решение неправильное, так как приводит к различному поведению компилятора в случае пустых структур и тех, которые содержат поля. Нет никакого противоречия требовать явной инициализации пустой структуры по default или new MyStruct(), так как в этом случае добавление поля в структуру гарантированно не вызовет никаких изменений в вызывающем коде.


А сейчас это не так. Впрочем, это не особо критическая проблема. Но пообщаться было интересно.

Жаль, что раньше этот комментарий не увидел и написал ниже то же. Есть ли логическое объяснение этой дичи? Зачем делать исключение для пустых структур, особенно если учесть, что пустая структура бессмысленна сама по себе?

Проверил этот код не только на NET 5, но и на Mono 6.8.0.105. Поведение ref и out абсолютно идентичное: пустая структура не требует инициализации. Я не знаю чем это объяснить, готов поверить в мировой заговор рептилоидов. :)

Не так то, что в обоих случаях я объявил пустые типы данных. И поведение компилятора разное. Потому что в случае со структурой компилятор знает, что ему нечего инициализировать, и не генерирует


// [38 13 - 38 27]
    IL_0001: ldarg.0      // obj
    IL_0002: initobj      WebUiTranslate.WeatherForecast/MyStruct

Это можно рассматривать как оптимизацию. Ок, тогда пусть он оптимизирует инициализацию вроде obj = default;, но все же требует ее присутсвие в исходном файле.


А то сейчас и это компилируется, когда структура пустая:


        MyStruct test;
        CheckYourself(ref test);
        private struct MyStruct 
        {
            //public int a;
        }
         private static void CheckYourself(ref MyStruct obj)
        {
            //obj = default;
        }

Небольшое дополнение, чисто поржать...


        private static void CheckYourself(out ITestInterface obj)
        {
        }
        private interface ITestInterface
        {
        }

Так нельзя!!!
WeatherForecast.cs(21, 29): [CS0177] The out parameter 'obj' must be assigned to before control leaves the current method


        private static void CheckYourself(out MyStruct obj)
        {
        }

        private struct MyStruct : ITestInterface
        {
        }

        private interface ITestInterface
        {
        }

А вот так — нормально!!! :)

RouR, я прочитал статью. И вижу, что в текущей реализации C# компилятора есть расхождение со стандартом. Тоесть это баг, который возможно будет исправлен в следующих версиях.


DistortNeo, отвечу тут, так как у меня коментарии все еще на премодерации.
[NotNullWhen] не более, чем атрибут, который указывает синтаксическому анализатору о том, что он должен игнорировать проверки на null, если метод возвращает false. Out параметр приходится инициализировать в любом случае. Если такое поведение не устраивает, то можно использовать ref параметр, который не требует обязательной инициализации в теле метода. В стандарте с логикой все в порядке и мое "бесит" — очень субъективно. :)


Просто исторически так сложилось, что код вроде


if (int.TryParse("99", out int num))
{
   .....
}

использует out параметры. По идее, это дает гарантию, что переменная num всегда будет инициализирована каким-либо значением после вызова метода. Но, как видно из статьи, это не всегда так.

Правильно, out параметры не должны быть инициализированы до вызова метода, но они должны быть инициализированы в теле метода.


public bool GetRegripPosition(MeshCalculationContext context, 
            ILinearAxis axis, Position axisOffset, 
            [NotNullWhen(returnValue:true)] out Position regripPosition)
{
            if (ВСЕ ХОРОШО)
            {
                   regripPosition = ЧТО-ТО ОСМЫСЛЕННОЕ;
                   return true;
            }

            regripPosition = default!; // ЭТО ВООБЩЕ НЕ ИМЕЕТ СМЫСЛА И ВРЕМЕНАМИ БЕСИТ, НО СТАНДАРТ ТРЕБУЕТ
            return false;
}
Там крайне жесткие рекомендации, потому что сервис kubelet просто не стартует с включенным свопом. Но, есть возможность указать в его параметрах командной строки, чтобы он игнорировал проверку наличия свопа.
2

Information

Rating
Does not participate
Registered
Activity