0

sqlite 및 regex 패턴 검색 작업에 가까운 C 속도를 얻고 싶습니다. 저는 다른 라이브러리와 FTS4에 대해 알고 있습니다. 더 빠르고 대안적인 솔루션이 될 것입니다. 그러나 그것은 제가 묻고있는 것이 아닙니다.파이썬의 함수형 프로그래밍을 사용하여 인터프리터와 메소드 오버 헤드를 완전히 피할 수 있습니까?

람다 또는 정의 된 메서드 또는 파이썬 코드를 사용하지 않는 한 CPython에 의해 노출 된 특정 프리미티브 및 C 수준 함수를 sqlite 사용자 지정 함수로 직접 주입 할 수 있으며 실행할 때, 상수를 반환하는 것을 제외하고 수행 된 작업이 없더라도 10 배의 부스트가 달성됩니다. 그러나 확장 기능을 만들 준비가 아니며 Cython과 같은 도구를 사용하여 C와 Python을 함께 사용하지 않아도됩니다.

필자는 이러한 성능 차이를 노출시키고 타사 라이브러리 인 cytoolz (작성 방법)에서 제공하는 몇 가지 빠른 속도를 사용하여 lambdas를 피하면서 일부 기능 스타일 논리를 구현하는 다음 테스트 코드를 고안했습니다. (: 창 8.1 64 비트 홈 OS), 생략 print 문 : 파이썬 2.7.8 32 비트와

import sqlite3 
import operator 
from cytoolz import functoolz 
from functools import partial 
from itertools import ifilter,chain 
import datetime 
from timeit import repeat 
import re,os 
from contextlib import closing 
db_path='testdb.sqlite' 
existed=os.path.exists(db_path) 
re_pat=re.compile(r'l[0-3]+') 
re_pat_match=re.compile(r'val[0-3]+') 
with closing(sqlite3.connect(db_path)) as co, co as co: 
    if not existed: 
     print "creating test data" 
     co.execute('create table test_table (testval TEXT)') 
     co.executemany('insert into test_table values (?)',(('val%s'%v,) for v in xrange(100000))) 

    def count(after_from=''): 
     print co.execute('select count(*) from test_table %s'%(after_from,)).fetchone()[0] 

    def python_return_true(v): 
     return True 

    co.create_function('python_return_true',1,python_return_true) 
    co.create_function('python_lambda_true',1,lambda x: True) 
    co.create_function('custom_lower',1,operator.methodcaller('lower')) 
    co.create_function('custom_composed_match',1,functoolz.compose(partial(operator.is_not,None),re_pat_match.match)) 
    data=[None,type('o',(),{"group":partial(operator.truth,0)})] # create a working list with a fallback object 
    co.create_function('custom_composed_search_text',1,functoolz.compose(
     operator.methodcaller('group'), # call group() on the final element (read these comments in reverse!) 
     next, # convert back to single element. list will either be length 1 or 2 
     partial(ifilter,None), # filter out failed search (is there a way to emulate a conditional method call via some other method??) 
     partial(chain,data), # iterate list (will raise exception if it reaches result of setitem which is None, but it never will) 
     partial(data.__setitem__,0), # set search result to list 
     re_pat.search # first do the search 
    )) 
    co.create_function('custom_composed_search_bool',1,functoolz.compose(partial(operator.is_not,None),re_pat.search)) 
    _search=re_pat.search # prevent an extra lookup in lambda 
    co.create_function('python_lambda_search_bool',1,lambda _in:1 if _search(_in) else None) 
    co.create_function('custom_composed_subn_alternative',1,functoolz.compose(operator.itemgetter(1),partial(re_pat.subn,'',count=1))) 
    for to_call,what in (
      (partial(count,after_from='where 1'),'pure select'), 
      (partial(count,after_from='where testval'),'select with simple compare'), 
      (partial(count,after_from='where python_return_true(testval)'),'select with python def func'), 
      (partial(count,after_from='where python_lambda_true(testval)'),'select with python lambda'), 
      (partial(count,after_from='where custom_lower(testval)'),'select with python lower'), 
      (partial(count,after_from='where custom_composed_match(testval)'),'select with python regex matches'), 
      (partial(count,after_from='where custom_composed_search_text(testval)'),'select with python regex search return text (chain)'), 
      (partial(count,after_from='where custom_composed_search_bool(testval)'),'select with python regex search bool (chain)'), 
      (partial(count,after_from='where python_lambda_search_bool(testval)'),'select with python regex search bool (lambda function)'), 
      (partial(count,after_from='where custom_composed_subn_alternative(testval)'),'select with python regex search (subn)'), 
    ): 
     print '%s:%s'%(what,datetime.timedelta(0,min(repeat(to_call,number=1)))) 

출력 아마 "의 몇 가지 변화와 함께 갈거야

pure select:0:00:00.003457 
select with simple compare:0:00:00.010253 
select with python def func:0:00:00.530252 
select with python lambda:0:00:00.530153 
select with python lower:0:00:00.051039 
select with python regex matches:0:00:00.066959 
select with python regex search return text (chain):0:00:00.134115 
select with python regex search bool (chain):0:00:00.067687 
select with python regex search bool (lambda function):0:00:00.576427 
select with python regex search (subn):0:00:00.136042 

위의 python regex search bool (chain) "을 선택하십시오. 그래서 제 질문은 2 부분입니다. create_function() 호출이 이해할 수있는 원시적 아무것도하지만 반환하는 함수를 만드는 경우

  1. sqlite3를은 "null이 아닌"검색() 따라서 체인, 변환 할 필요를 반환하는 MatchObject 때문에 실패합니다 방법. 검색 텍스트를 반환하는 함수의 경우 원본에서 볼 수있는 것처럼보기 흉하게 나타납니다. 비 파이썬 함수를 선택적으로 sqlite3과 함께 사용하기 위해 정규식을 검색 한 후 반환되는 경우에만 MatchObject의 그룹을 표시하려고 할 때 사용한 요소 대 반복자 변환 전략보다 쉬운 대안이 있습니까?

  2. 파이썬 함수보다 데이터베이스 함수를 사용할지 아니면 사전 또는 객체 대신 목록을 사용할지, 추가 메서드 대신 생성자를 사용하여 변수 이름을 로컬 네임 스페이스에 복사하는 코드 줄을 낭비할지 여부는 계속해서 논쟁 중입니다. 파이썬이 제공 할 수있는 추상화로부터 이익을 얻는 대신 루프, 함수 또는 인라인 (inlining) 루프를 호출 할 수 있습니다. 스캐 폴딩을 위해 여전히 파이썬을 사용하는 동안 나는 엄청난 효율성을 달성 할 수있는 다른 기능/라이브러리를 무엇을 고려해야 하는가? 실제로 파이썬 코드 자체 (피피, 사이먼)의 속도를 높이는 프로그램을 알고 있지만 파이썬의 언어 구조가 코드를 항상 '해석 된'것으로 가정하기 때문에 사용하는 것이 더 위험하거나 여전히 불편을 겪고있는 것처럼 보입니다. 아마도 빠른 텍스트 처리의 영역에서 갚을 수있는 몇 가지 유형의 메소드와 전략이있을 것입니다. 나는 과학적, 통계적, 수학적 속도 향상에 중점을 둔 도서관을 알고 있지만, 나는 그 영역에 특별히 관심이 없다.

답변

0

최근 테스트를 수행하고 텍스트 처리 작업의 속도를 높이는 다른 방법을 살펴 보았습니다. 중요한 돌파구, 그리고 파이썬이 할 수있는 좋은 점은 메타 프로그래밍입니다. 텍스트 파일의 행에 특정 작업을 수행하는 코드 스 니펫을 결합하고 변환하는 코드를 작성합니다. 메서드 오버 헤드는 모두 하나의 메서드이기 때문에 제거되며, 또 다른 주요 이점은 배열 인덱스 조회 또는 트레이드 오프가 허용되는 경우 자동 특성 로컬 매핑에 특성을 자동으로 다시 매핑하는 것입니다. 코드 스 니펫은 그대로 있고 다른 스 니펫의 일부로 실행 및 테스트 할 수있는 방식으로 작성할 수 있습니다. 컴파일 된 파이썬 소스 코드의 결과에 주석으로 추가 할 수 있습니다.

이것은 항상 파이썬에 머무르고 항상 해석 된 언어의 성능 함정에 대해 걱정하지 않고 언어가 제공 할 수있는 모든 이점을 얻는 가장 쉬운 방법입니다.

귀하의 기고에 참여한 54 명의 시청자 여러분 께 감사드립니다. ;)