Эмуляция статических переменных функции с использованием статических полей threadstatic?

#c# #static #thread-safety #local-variables

#c# #статический #безопасность потоков #локальные переменные

Вопрос:

Для некоторых статических методов я понимаю, что чрезвычайно удобно использовать небольшой массив для временного хранения значений во время операции. Указанный массив полезен, потому что вам нужно индексировать, но выделять этот небольшой массив каждый раз, когда вызывается метод.

Является ли это хорошим способом обойти отсутствие C-подобных статических локальных в C #?

 [ThreadStatic]private static int[] staticregister = new int[4];

public static bool CoolStaticMethod(int[] largearray)
{
    //...
}
  

Я предполагаю, что метод, который не может вызывать себя ни напрямую (рекурсивно), ни косвенно, может вызываться только в одном потоке, поэтому поддельный статический локальный файл должен быть объявлен потоковым статическим, и проблема в целом решена.

Редактировать:

Я должен добавить, что содержимое регистра является мусором между вызовами метода.

Комментарии:

1. ДА . [Просто заполнитель, чтобы иметь возможность комментировать]

Ответ №1:

Это не то, что я бы назвал хорошим обходным путем, нет. Это сработает (при условии, что вы уверены в рисках повторного входа, т. Е. Не вызываете себя, даже через случайные события / обратные вызовы / и т.д.) — Но…

На мой взгляд, это с сохранением состояния, сделайте это экземпляром:

 private int[] register = new int[4];
public bool CoolMethod(int[] largearray) {...}
  

и просто используйте разные экземпляры WheverTheTypeIs для каждого контекста, т. Е. Экземпляр действует как контекст. Просто используйте другой экземпляр для каждого потока, если вам нужен контекст для каждого потока. Это также позволяет продолжать использование с обратными вызовами, параллелизмом, рабочими и т.д. В том же контексте. Обратите внимание, что существует множество фреймворков, которые не гарантируют единый поток (WCF, ASP.NET , WPF для примеров), и это только увеличится, поскольку 5.0 вводит больше async / await ориентированного кода.

Если вы глубоко привязаны к статическим методам, передачи register в качестве второго параметра также было бы достаточно:

 public static bool CoolStaticMethod(int[] largearray, int[] register) {...}
  

Если проблема заключается в выделении 4-байтового массива:

  1. обычно это будет GEN-0, поэтому собирать его так дешево
  2. если вы действительно хотите, используйте stackalloc и unsafe , чтобы избежать выделения

Для примера «2»:

 public static unsafe bool CoolStaticMethod(int[] largearray)
{
    // not an array! this is raw data on the stack; DO NOT GO OUT OF BOUNDS!
    int* register = stackalloc int[4]; 

    register[0] = 1;
    register[1] = largearray[3];
    largearray[2] = register[0];
    ....
}
  

Комментарии:

1. Ваше предложение передать рабочий буфер / регистр только усложняет дизайн клиентского кода, который зависит от сервисов статического метода.

2. @Cecil k; как насчет последнего предложения, если проблема заключается в выделении крошечного массива (о котором, кстати, я действительно не думаю, что вам нужно беспокоиться)

3. @Cecil plus, если вы ориентируетесь на распределение, вы могли бы избежать этого с помощью микро-пула; дайте мне знать, если хотите пример

4. Честно говоря, мое первоначальное беспокойство по поводу задержки распределения и GC’ing на самом деле не критично, пока я не проведу некоторое профилирование, чтобы увидеть, что это действительно может быть проблемой. Насколько я знаю, JIT и GC могли бы видеть шаблон использования и размещать массив в стеке и извлекать его при возврате.

5. @Cecil этого не произойдет (если вы не используете stackalloc) — однако он будет выделяться на GEN-0 и умирать на GEN-0, что действительно дешево проверить. Конечно, это зависит от использования, но я бы не стал зацикливаться на этом, если это не называется lots.