Вместо запуска цикла For
по всему (!) Столбцу вы можете сначала проверить, есть ли что-то в столбце, а затем .Find
искомое значение. Если вы нашли результат, вы можете использовать его номер строки.
Вместо копирования / вставки вы можете просто назначить Range.Value
для получения значений без форматирования.
Этот код копирует значения всей строки четырьмя строками ниже.
Sub Test()
Dim ws As Worksheet
Dim c As Range
Set ws = ActiveSheet
If WorksheetFunction.CountA(ws.Columns(2)) > 0 Then
Set c = ws.Columns(2).Find( _
What:="Total WI Expenses", _
After:=ws.Cells(1, 2), _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext)
If Not c Is Nothing Then
ws.Rows(c.Row + 4).Value = ws.Rows(c.Row).Value
End If
Set c = Nothing
End If
Set ws = Nothing
End Sub
Скорость зависит от реализации TLS.
Да, Вы корректны, что TLS может быть с такой скоростью, как поиск указателя. Это может даже быть быстрее в системах с блоком управления памятью.
Для поиска указателя Вы нуждаетесь в помощи от планировщика все же. Планировщик должен - на переключении задач - обновляют указатель на данные TLS.
Другой быстрый способ реализовать TLS через Блок управления памятью. Здесь TLS рассматривают как любые другие данные за исключением того, что переменные TLS выделяются в специальном сегменте. Планировщик будет - на переключении задач - отображают корректный блок памяти в адресное пространство задачи.
, Если планировщик не поддерживает ни одного из этих методов, компилятор/библиотека должен сделать следующее:
, Очевидно, выполнение все это для каждого доступа к данным TLS требует времени и, возможно, нуждается в трех вызовах ОС: Получение ThreadId, Возьмите и Выпуск семафор.
семафор является btw, требуемым не удостоверяться никакие чтения потока из списка указателя TLS, в то время как другой поток посреди порождения нового потока. (и как таковой выделяют новый блок TLS и изменяют datastructure).
, К сожалению, весьма распространено видеть медленную реализацию TLS на практике.
Нужно быть очень осторожным в интерпретации результатов сравнительного теста. Например, недавний поток в группах новостей D, заключенных из сравнительного теста, что генерация кода dmd вызывала основное замедление в цикле, который сделал арифметику, но в действительности проведенное время было во власти функции помощника во время выполнения, которая сделала деление в столбик. Генерация кода компилятора не имела никакого отношения к замедлению.
Для наблюдения, какой код сгенерирован для tls скомпилируйте и obj2asm этот код:
__thread int x;
int foo() { return x; }
TLS реализован очень по-другому в Windows, чем на Linux и будет очень отличаться снова на OSX. Но во всех случаях это будет намного больше инструкций, чем простая загрузка местоположения статического ЗУ. TLS всегда будет медленным относительно простого доступа. Доступ к TLS globals в жестком цикле будет медленным, также. Попытайтесь кэшировать значение TLS во временном файле вместо этого.
я написал некоторый код выделения пула потоков несколько лет назад и кэшировал дескриптор TLS к пулу, который работал хорошо.
Мы наблюдали похожие проблемы с производительностью при использовании TLS (в Windows). Мы полагаемся на него для некоторых критических операций внутри «ядра» нашего продукта. После некоторых усилий я решил попробовать и улучшить его.
Я рад сообщить, что теперь у нас есть небольшой API, который предлагает более чем 50% сокращение Процессорное время для эквивалентной операции, когда вызывающий поток не «знает» свой идентификатор потока и сокращение> 65%, если вызывающий поток уже получил свой идентификатор потока (возможно, для какого-либо другого более раннего шага обработки).
function (get_thread_private_ptr ()) всегда возвращает указатель на структуру, которую мы используем внутри для хранения всех видов, поэтому нам нужен только один для каждого потока.
В общем, я думаю, что поддержка Win32 TLS действительно плохо продумана.
Если вы не можете использовать поддержку TLS компилятора, вы можете управлять TLS самостоятельно. Я создал шаблон оболочки для C ++, поэтому базовую реализацию легко заменить. В этом примере , я реализовал его для Win32. Примечание. Поскольку вы не можете получить неограниченное количество индексов TLS для каждого процесса (по крайней мере, в Win32), вы должны указать на блоки кучи, достаточно большие для хранения все данные, относящиеся к потоку. Таким образом, у вас будет минимальное количество индексов TLS и связанных запросов. В «лучшем случае» у вас будет всего 1 указатель TLS, указывающий на один частный блок кучи за поток.
В двух словах: не указывайте на отдельные объекты, вместо этого указывайте на конкретный поток, память кучи / контейнеры, содержащие указатели на объекты, для достижения лучшей производительности.
Не забывайте освобождать память, если она больше не используется. Я делаю это, помещая поток в класс (как это делает Java) и обрабатываю TLS конструктором и деструктором. {{1} } Кроме того, я храню часто используемые данные, такие как дескрипторы потоков и идентификаторы, в качестве членов класса.
для типа *: tl_ptr
для константного типа *: tl_ptr
для типа * const: {{1 }} const tl_ptr
const type * const: const tl_ptr
template<typename T>
class tl_ptr {
protected:
DWORD index;
public:
tl_ptr(void) : index(TlsAlloc()){
assert(index != TLS_OUT_OF_INDEXES);
set(NULL);
}
void set(T* ptr){
TlsSetValue(index,(LPVOID) ptr);
}
T* get(void)const {
return (T*) TlsGetValue(index);
}
tl_ptr& operator=(T* ptr){
set(ptr);
return *this;
}
tl_ptr& operator=(const tl_ptr& other){
set(other.get());
return *this;
}
T& operator*(void)const{
return *get();
}
T* operator->(void)const{
return get();
}
~tl_ptr(){
TlsFree(index);
}
};