2

大きなファイルからリストを読み取っていますが、最終的には s として保存したいと考えていarray.arrayます。なぜなら

map(int, line.split())

は非常に遅いので、strtok を実行する小さな C モジュールと、より高速なバージョンの atoi を作成しました。

inline long
minhashTables_myatoi(const char* s)
{
    int r;
    for (r = 0; *s; r = r * 10 + *s++ - '0');
    return r;
}

static PyObject*
minhashTables_ints(PyObject *self, PyObject *args)
{
    char* s;
    Py_ssize_t slen;

    if(!PyArg_ParseTuple(args, "s#", &s, &slen))
        return NULL;

    long* buf = malloc(sizeof(long) * (slen+1)/2);

    const char* tok = strtok(s, " ");
    buf[0] = minhashTables_myatoi(tok);
    Py_ssize_t i;
    for(i = 1; (tok = strtok(NULL, " ")) != NULL; i++)
        buf[i] = minhashTables_myatoi(tok);

    Py_ssize_t buflen = i;
    PyObject* list = PyList_New(buflen);
    PyObject *o;
        for(i = 0; i < buflen; i++)
    {
        o = PyInt_FromLong(buf[i]);
        PyList_SET_ITEM(list, i, o);
    }
    free(buf);

    return list;
}

したがって、私の python スクリプトは文字列で呼び出し、それをコンストラクターにints()渡し、結果の配列を.array.arraylist

ints()私の問題は、スクリプトがメモリをリークすることです。もちろん、関数ではなくマップでは発生しませんでした。

また、C モジュールを使用して独自のバージョンの Pythonint()を使用しても、メモリ リークは発生しません。

ご協力いただきありがとうございます!

編集: モジュールをvalgrindするために、次のスクリプトを使用しました:

import minhashTables

data = ' '.join(map(str, range(10)))
print 'start'
foo = minhashTables.ints(data)
del data
del foo
print 'stop'

を実行しましたが、とvalgrind --tool=memcheck --leak-check=full --show-reachable=yes python test.pyの間に valgrind からの出力がないため、前後にトンがあります。startstop

編集:リークしていることを確認するためのコード: import minhashTables

for i in xrange(1000000000):
    data = ' '.join(map(str, range(10, 10000)))
    foo = minhashTables.ints(data)

strtok によって変更されるため、文字列を再作成する必要があります。ちなみに、文字列を別のメモリ位置にコピーしても動作は変わりません。

4

3 に答える 3

2

Valgrindをご覧になることをお勧めします。これは、Cのメモリリークの根底に到達するための非常に便利なツールです。

于 2011-02-10T10:01:49.553 に答える
1

mallocこれらすべての s のために本当にスペースを空ける必要がありますlongか?

私は Python/C API に詳しくないので、これはひどいアドバイスかもしれませんが、文字列を反復処理して、見つけた長さをリストに追加することはできませんか?

つまり、次のコードを使用します。

static const char* const testString = "12 345  67  8 910 11 1213 141516, 1718";

int main()
{
    const char* i = testString;
    long parseLong = 0;
    int gotLong = 0;

    for (;*i;++i)
    {
        if ('0' <= *i && *i <= '9')
        {
            parseLong = (parseLong * 10) + (*i - '0');
            gotLong = 1;
        }
        else if (gotLong)
        {
            printf("Got: %d\n", parseLong);
            parseLong = 0;
            gotLong = 0;
        }
    }

    if (gotLong)
        printf("Got: %d\n", parseLong);
}

そして、 を のprintfような適切な pythony-goodness に置き換えPyList_Append()ます。

を回避mallocし、メモリの使用量を減らし、一定の Python 文字列を安全に直接操作できるようにするだけでなく、このコードは、空の文字列、複数のスペース、その他の数値間の区切り文字などのコーナー ケースも処理します。


編集: long の カウント 最初に long の数をカウントしたい場合は、正しい長さの Python List を割り当てることができます。次に、次のようなものを追加するだけです。

    for (i = testString;*i;++i)
    {
        const int isdigitoflong = isdigit(*i);

        if (!gotLong && isdigitoflong)
            longCount++;

        gotLong = isdigitoflong;
    }

これは比較的速いはずです。


編集 2: より優れ
たパーサー 上記のパーサーのわずかに優れたバージョンを次に示します。これは、もう少しコンパクトでgotLong、最後の long を処理するためにコードを繰り返す必要がなく、コードを繰り返す必要もありません。

    for (i = testString;*i;++i)
    {
        if (isdigit(*i))
        {
            do {
                parseLong = (parseLong * 10) + (*i - '0');
            } while (*++i && isdigit(*i));

            printf("Got: %d\n", parseLong);
            parseLong = 0;
        }
    }   
于 2011-02-10T15:00:43.740 に答える
-1

これを試して

inline long
    minhashTables_myatoi(const char* s)
    {
        long result=0;
        while((*s)!='\0'){
            result = result * 10 + (*s- '0');
            s++;
        }
        return result;
    }
于 2011-02-10T09:46:42.000 に答える