Ищите список строк для любой подстроки из другого списка

Я не знаком с этим конкретным графическим процессором, но несколько вещей, которые выделяются как возможные красные флаги в вашем коде:

  • Это целочисленный код ALU, а не операции с плавающей запятой. , Многие графические процессоры вообще не оптимизированы для этого.
  • Я бы не стал полагаться на то, что компилятор оптимизирует вычисления смещения массива; особенно глупый компилятор может выдавать 3 целочисленных умножения для C[index + k * WIDTH] = A[index + k * WIDTH] + B[index + k * WIDTH]; на каждой итерации цикла. Я бы сохранял смещение в переменной и добавлял к нему на каждой итерации, умножение не требовалось.
  • 1000-итерация для цикла обычно выделяется как потенциальный источник лучшего параллелизма. Многие GPU плохо работают с долго работающими ядрами.
  • Шаблоны доступа к памяти кажутся неоптимальными. Попробуйте расположить так, чтобы смежные рабочие элементы в группе обращались к смежным ячейкам памяти. Локальный размер 2x2x2 кажется особенно плохим выбором. Вы пробовали 12x1x1?
  • Почему вы даже упорядочиваете рабочие элементы таким образом? Похоже, вы буквально рассчитываете C[i] = A[i] + B[i] для i = 0..1000*12*12*12. Как насчет написания вашего ядра именно так и представления 1728000 рабочих элементов в одном измерении? Это экономит на всех сложных расчетах индекса.

Если вы можете получить какие-либо отзывы от драйверов о том, с чем связан графический процессор (ALU, загрузка памяти, планирование потоков и т. Д.), Это очень поможет при выборе места для поиска. способы ускорить его.

19
задан Jason Coon 14 April 2009 в 20:56
поделиться

5 ответов

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

Поскольку вам все равно, какой элемент в списке содержит ключевое слово, вы можете отсканировать весь список один раз (в виде одной строки) вместо одного элемента в время. Для этого вам нужен вступительный персонаж, который, как вы знаете, выиграл t встречаются в ключевом слове, чтобы избежать ложных срабатываний. В этом примере я использую символ новой строки.

def check_data(data):
    s = "\n".join(data);
    for k in keywords:
        if k in s:
            return True

    return False

В моем совершенно ненаучном тесте моя версия проверяла список из 5000 элементов 100000 раз примерно за 30 секунд. Я остановил вашу версию через 3 минуты - надоело ждать поста =)

17
ответ дан 30 November 2019 в 02:13
поделиться

Вы ищете

any( k in s for k in keywords )

Это более компактно, но может быть менее эффективно.

38
ответ дан 30 November 2019 в 02:13
поделиться

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

Это может позволить им тестироваться параллельно, но очень сильно будет зависеть от того, что представляют собой ключевые слова (например, некоторая работа может быть повторно использована для проверки «привет» и «ад», вместо того, чтобы искать каждую фразу с самого начала для каждое слово.

Вы можете сделать это, выполнив:

import re
keyword_re = re.compile("|".join(map(re.escape, keywords)))

Затем:

>>> bool(keyword_re.search('hello, world'))
True
>>> bool(keyword_re.search('hi, earth'))
False

(Это на самом деле вернет объект совпадения для найденного и None, если не найден - это может быть полезно, если вам нужно знать, какое ключевое слово соответствует )

Тем не менее, сколько (если вообще что-то) этого выиграет, вы будете зависеть от ключевых слов. Если у вас есть только одно или два, сохраните свой текущий подход. Если у вас большой список, возможно, стоит посмотреть и профилировать, чтобы увидеть который работает лучше.

[Редактировать] Для справки вот как подходы подходят для вашего примера:

               good1   good2  good3   bad1   bad2
original     : 0.206   0.233  0.229   0.390   63.879
gnud (join)  : 0.257   0.347  4.600   0.281    6.706
regex        : 0.766   1.018  0.397   0.764  124.351
regex (join) : 0.345   0.337  3.305   0.481   48.666

Очевидно, что для этого случая ваш подход работает намного лучше, чем регулярный. Будет ли это всегда так, во многом зависит от количества и сложности ключевых слов, а также от входных данных, которые будут проверяться. Для большого количества ключевых слов, длинных списков или редко совпадающих фраз регулярные выражения могут работать лучше, но действительно получают информацию о времени и, возможно, пробуют даже более простые оптимизации (например, перемещение наиболее распространенных слов в начало ключевого слова). список) первый. Иногда самый простой подход - действительно лучший.

[Edit2] Обновлена ​​таблица с решением gnud и аналогичным подходом перед применением регулярных выражений. Я также добавил 2 новых теста:

good_data3 = good_data2 * 500  # 1000 items, the first of which matches.
bad_data2 = bad_data * 500     # 1000 items, none of which matches.

, которые показывают различные сильные и слабые стороны. Присоединение работает хуже, когда совпадение будет найдено немедленно (так как при присоединении к списку всегда есть предоплата, это лучший вариант для метода линейного поиска), однако для несоответствующих списков выполняется лучше. Гораздо лучше , когда в списке list.case имеется большое количество элементов).

2
ответ дан 30 November 2019 в 02:13
поделиться

If you have many keywords, you might want to try a suffix tree [1]. Insert all the words from the three data lists, storing which list each word comes from in it's terminating node. Then you can perform queries on the tree for each keyword really, really fast.

Warning: suffix trees are very complicated to implement!

[1] http://en.wikipedia.org/wiki/Suffix_tree

4
ответ дан 30 November 2019 в 02:13
поделиться

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

0
ответ дан 30 November 2019 в 02:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: