αžŸαŸ’αž‘αŸ’αžšαžΈαž˜αž‘αž·αž“αŸ’αž“αž“αŸαž™αž‡αž½αžšαžˆαžšαž‡αžΆαž˜αž½αž™ Apache Arrow

αž€αžΆαžšαž”αž€αž”αŸ’αžšαŸ‚αž’αžαŸ’αžαž”αž‘αžαŸ’αžšαžΌαžœαž”αžΆαž“αžšαŸ€αž”αž…αŸ†αž‡αžΆαž–αž·αžŸαŸαžŸαžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαž·αžŸαŸ’αžŸαž“αŸƒαžœαž‚αŸ’αž‚αžŸαž·αž€αŸ’αžŸαžΆ "αžœαž·αžŸαŸ’αžœαž€αžšαž‘αž·αž“αŸ’αž“αž“αŸαž™".

αžŸαŸ’αž‘αŸ’αžšαžΈαž˜αž‘αž·αž“αŸ’αž“αž“αŸαž™αž‡αž½αžšαžˆαžšαž‡αžΆαž˜αž½αž™ Apache Arrow

αž”αŸ‰αž»αž“αŸ’αž˜αžΆαž“αžŸαž”αŸ’αžαžΆαž αŸαž€αž“αŸ’αž›αž„αž˜αž€αž“αŸαŸ‡ αž™αžΎαž„αž˜αžΆαž“ αžŽαž„αž›αžΈ αž”αž“αŸ’αžαŸ‚αž˜αž‘αŸ… αž–αŸ’αžšαž½αž‰αž’αžΆαž”αŸ‰αžΆαž… αž‘αž˜αŸ’αžšαž„αŸ‹αž€αžΆαžšαžŸαŸ’αž‘αŸ’αžšαžΈαž˜αž”αŸ’αžšαž–αŸαž“αŸ’αž’αž‚αŸ„αž›αž–αžΈαžš αž”αŸ†αž–αŸαž‰αž”αž“αŸ’αžαŸ‚αž˜αž€αžΆαžšαž…αžΌαž›αž”αŸ’αžšαžΎαžŠαŸ„αž™αž…αŸƒαžŠαž“αŸ’αž™/αž‘αž˜αŸ’αžšαž„αŸ‹αž―αž€αžŸαžΆαžš IPC αžŠαŸ‚αž›αž˜αžΆαž“αžŸαŸ’αžšαžΆαž”αŸ‹αŸ” αž™αžΎαž„αž˜αžΆαž“αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αž Java αž“αž·αž„ C++ αž“αž·αž„αž€αžΆαžšαž…αž„ Python αŸ” αž“αŸ…αž€αŸ’αž“αž»αž„αž’αžαŸ’αžαž”αž‘αž“αŸαŸ‡ αžαŸ’αž‰αž»αŸ†αž“αžΉαž„αž–αž“αŸ’αž™αž›αŸ‹αž–αžΈαžšαž”αŸ€αž”αžŠαŸ‚αž›αž‘αž˜αŸ’αžšαž„αŸ‹αžŠαŸ†αžŽαžΎαžšαž€αžΆαžš αž“αž·αž„αž”αž„αŸ’αž αžΆαž‰αž–αžΈαžšαž”αŸ€αž”αžŠαŸ‚αž›αž’αŸ’αž“αž€αž’αžΆαž…αžŸαž˜αŸ’αžšαŸαž…αž”αžΆαž“αž“αžΌαžœαž‘αž·αž“αŸ’αž“αž“αŸαž™αž€αž˜αŸ’αžšαž·αžαžαŸ’αž–αžŸαŸ‹αž”αŸ†αž•αž»αžαžŸαž˜αŸ’αžšαžΆαž”αŸ‹ DataFrame αžαŸ’αž›αžΆαžƒαŸ’αž˜αž»αŸ†αž•αŸαž“αžŠαžΆαŸ”

αžŸαŸ’αž‘αŸ’αžšαžΈαž˜αž‘αž·αž“αŸ’αž“αž“αŸαž™αž‡αž½αžšαžˆαžš

αžŸαŸ†αžŽαž½αžšαž‘αžΌαž‘αŸ…αžŠαŸ‚αž›αžαŸ’αž‰αž»αŸ†αž‘αž‘αž½αž›αž”αžΆαž“αž–αžΈαž’αŸ’αž“αž€αž”αŸ’αžšαžΎαž”αŸ’αžšαžΆαžŸαŸ‹ Arrow αž‚αžΊαž€αžΆαžšαž…αŸ†αžŽαžΆαž™αžαŸ’αž–αžŸαŸ‹αž€αŸ’αž“αž»αž„αž€αžΆαžšαž•αŸ’αž‘αŸαžšαž‘αž·αž“αŸ’αž“αž“αŸαž™αžαžΆαžšαžΆαž„αž‡αžΆαž…αŸ’αžšαžΎαž“αž–αžΈαž‡αž½αžšαžŠαŸαž€ αž¬αž‘αž˜αŸ’αžšαž„αŸ‹αžαž˜αŸ’αžšαž„αŸ‹αž‘αž·αžŸαž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαž‘αŸ…αž‡αžΆαž‘αž˜αŸ’αžšαž„αŸ‹αžαž˜αŸ’αžšαž„αŸ‹αž‡αž½αžšαŸ” αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαŸ†αžŽαž»αŸ†αž‘αž·αž“αŸ’αž“αž“αŸαž™αž…αŸ’αžšαžΎαž“αž‡αžΈαž αŸ’αž‚αžΆαž”αŸƒ αž€αžΆαžšαž”αž‰αŸ’αž‡αžΌαž“αž“αŸ…αž€αŸ’αž“αž»αž„αž’αž„αŸ’αž‚αž…αž„αž…αžΆαŸ† αž¬αž“αŸ…αž›αžΎαžαžΆαžŸαž’αžΆαž…αž‡αžΆαž€αž·αž…αŸ’αž…αž€αžΆαžšαžŠαŸαž›αžΎαžŸαž›αž”αŸ‹αŸ”

αžŠαžΎαž˜αŸ’αž”αžΈαžŸαŸ’αž‘αŸ’αžšαžΈαž˜αž‘αž·αž“αŸ’αž“αž“αŸαž™ αž˜αž·αž“αžαžΆαž‘αž·αž“αŸ’αž“αž“αŸαž™αž”αŸ’αžšαž—αž–αž‡αžΆαž‡αž½αžš αž¬αž‡αž½αžšαžˆαžšαž“αŸ„αŸ‡αž‘αŸ αž‡αž˜αŸ’αžšαžΎαžŸαž˜αž½αž™αž‚αžΊαžαŸ’αžšαžΌαžœαž•αŸ’αž‰αžΎαž‡αž½αžšαžαžΌαž…αŸ—αž‡αžΆαž€αŸ’αžšαž»αž˜αŸ— αžŠαŸ‚αž›αž“αžΈαž˜αž½αž™αŸ—αž˜αžΆαž“αž”αŸ’αž›αž„αŸ‹αž‡αž½αžšαžˆαžšαž“αŸ…αžαžΆαž„αž€αŸ’αž“αž»αž„αŸ”

αž“αŸ…αž€αŸ’αž“αž»αž„ Apache Arrow αž€αžΆαžšαž”αŸ’αžšαž˜αžΌαž›αž’αžΆαžšαŸαž‡αž½αžšαžˆαžšαž€αŸ’αž“αž»αž„αžŸαžαž·αžŠαŸ‚αž›αžαŸ†αžŽαžΆαž„αž±αŸ’αž™αž€αŸ†αžŽαžΆαžαŸ‹αžαžΆαžšαžΆαž„αžαŸ’αžšαžΌαžœαž”αžΆαž“αž‚αŸαž αŸ…αžαžΆ αž”αžΆαž…αŸ‹αž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαŸ” αžŠαžΎαž˜αŸ’αž”αžΈαžαŸ†αžŽαžΆαž„αž±αŸ’αž™αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αž‘αž·αž“αŸ’αž“αž“αŸαž™αžαŸ‚αž˜αž½αž™αž“αŸƒαžαžΆαžšαžΆαž„αž‘αžΌαž‡αžΈαžαž› αž”αžŽαŸ’αžαž»αŸ†αž“αŸƒαž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαž‡αžΆαž…αŸ’αžšαžΎαž“αž’αžΆαž…αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αŸ’αžšαž˜αžΌαž›αŸ”

αž“αŸ…αž€αŸ’αž“αž»αž„αž‘αž˜αŸ’αžšαž„αŸ‹αž―αž€αžŸαžΆαžš "αž€αžΆαžšαž…αžΌαž›αž”αŸ’αžšαžΎαžŠαŸ„αž™αž…αŸƒαžŠαž“αŸ’αž™" αžŠαŸ‚αž›αž˜αžΆαž“αžŸαŸ’αžšαžΆαž”αŸ‹ αž™αžΎαž„αž€αžαŸ‹αžαŸ’αžšαžΆαž‘αž·αž“αŸ’αž“αž“αŸαž™αž˜αŸαžαžΆαžŠαŸ‚αž›αž˜αžΆαž“αž‚αŸ’αžšαŸ„αž„αž€αžΆαžšαžŽαŸαžαžΆαžšαžΆαž„ αž“αž·αž„αž‘αžΈαžαžΆαŸ†αž„αž”αŸ’αž›αž»αž€αž“αŸ…αž…αž»αž„αž”αž‰αŸ’αž…αž”αŸ‹αž“αŸƒαž―αž€αžŸαžΆαžš αžŠαŸ‚αž›αž’αž“αž»αž‰αŸ’αž‰αžΆαžαž±αŸ’αž™αž’αŸ’αž“αž€αž‡αŸ’αžšαžΎαžŸαžšαžΎαžŸαž€αž˜αŸ’αžšαž„αž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαžŽαžΆαž˜αž½αž™ αž¬αž‡αž½αžšαžˆαžšαžŽαžΆαž˜αž½αž™αž–αžΈαžŸαŸ†αžŽαž»αŸ†αž‘αž·αž“αŸ’αž“αž“αŸαž™αž€αŸ’αž“αž»αž„αžαž˜αŸ’αž›αŸƒαžαŸ„αž€αž”αŸ†αž•αž»αžαŸ” αž€αŸ’αž“αž»αž„αž‘αž˜αŸ’αžšαž„αŸ‹αž€αžΆαžšαž•αŸ’αžŸαžΆαž™ αž™αžΎαž„αž•αŸ’αž‰αžΎαžŸαžΆαžšαž‡αžΆαžŸαŸŠαŸαžšαžΈαŸ– αž‚αŸ’αžšαŸ„αž„αž˜αž½αž™ αž αžΎαž™αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€αž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαž˜αž½αž™ αž¬αž…αŸ’αžšαžΎαž“αŸ”

αž‘αž˜αŸ’αžšαž„αŸ‹αž•αŸ’αžŸαŸαž„αŸ—αž‚αŸ’αž“αžΆαž˜αžΎαž›αž‘αŸ…αžŠαžΌαž…αž“αŸαŸ‡αŸ–

αžŸαŸ’αž‘αŸ’αžšαžΈαž˜αž‘αž·αž“αŸ’αž“αž“αŸαž™αž‡αž½αžšαžˆαžšαž‡αžΆαž˜αž½αž™ Apache Arrow

αžŸαŸ’αž‘αŸ’αžšαžΈαž˜αž‘αž·αž“αŸ’αž“αž“αŸαž™αž“αŸ…αž€αŸ’αž“αž»αž„ PyArrow: αž€αž˜αŸ’αž˜αžœαž·αž’αžΈ

αžŠαžΎαž˜αŸ’αž”αžΈαž”αž„αŸ’αž αžΆαž‰αž’αŸ’αž“αž€αž–αžΈαžšαž”αŸ€αž”αžŠαŸ‚αž›αžœαžΆαžŠαŸ†αžŽαžΎαžšαž€αžΆαžš αžαŸ’αž‰αž»αŸ†αž“αžΉαž„αž”αž„αŸ’αž€αžΎαžαžŸαŸ†αžŽαž»αŸ†αž‘αž·αž“αŸ’αž“αž“αŸαž™αž§αž‘αžΆαž αžšαžŽαŸαžŠαŸ‚αž›αžαŸ†αžŽαžΆαž„αž±αŸ’αž™αž€αŸ†αžŽαžΆαžαŸ‹αžŸαŸ’αž‘αŸ’αžšαžΈαž˜αžαŸ‚αž˜αž½αž™αŸ–

import time
import numpy as np
import pandas as pd
import pyarrow as pa

def generate_data(total_size, ncols):
    nrows = int(total_size / ncols / np.dtype('float64').itemsize)
    return pd.DataFrame({
        'c' + str(i): np.random.randn(nrows)
        for i in range(ncols)
    })	

αž₯αž‘αžΌαžœαž“αŸαŸ‡ αž§αž”αž˜αžΆαžαžΆαž™αžΎαž„αž…αž„αŸ‹αžŸαžšαžŸαŸαžšαž‘αž·αž“αŸ’αž“αž“αŸαž™ 1 GB αžŠαŸ‚αž›αž˜αžΆαž“αž”αŸ†αžŽαŸ‚αž€αž“αŸƒ 1 MB αž“αžΈαž˜αž½αž™αŸ—αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžŸαžšαž»αž”αž…αŸ†αž“αž½αž“ 1024 αž€αŸ†αžŽαžΆαžαŸ‹αŸ” αžŠαžΎαž˜αŸ’αž”αžΈαž…αžΆαž”αŸ‹αž•αŸ’αžαžΎαž˜ αž…αžΌαžšαž™αžΎαž„αž”αž„αŸ’αž€αžΎαžαžŸαŸŠαž»αž˜αž‘αž·αž“αŸ’αž“αž“αŸαž™ 1 MB αžŠαŸ†αž”αžΌαž„αžŠαŸ‚αž›αž˜αžΆαž“ 16 αž‡αž½αžšαžˆαžšαŸ–

KILOBYTE = 1 << 10
MEGABYTE = KILOBYTE * KILOBYTE
DATA_SIZE = 1024 * MEGABYTE
NCOLS = 16

df = generate_data(MEGABYTE, NCOLS)

αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€αžαŸ’αž‰αž»αŸ†αž”αŸ†αž”αŸ’αž›αŸ‚αž„αž–αž½αž€αžœαžΆαž‘αŸ…αž‡αžΆ pyarrow.RecordBatch:

batch = pa.RecordBatch.from_pandas(df)

αž₯αž‘αžΌαžœαž“αŸαŸ‡αžαŸ’αž‰αž»αŸ†αž“αžΉαž„αž”αž„αŸ’αž€αžΎαžαžŸαŸ’αž‘αŸ’αžšαžΈαž˜αž‘αž·αž“αŸ’αž“αž•αž›αžŠαŸ‚αž›αž“αžΉαž„αžŸαžšαžŸαŸαžšαž‘αŸ… RAM αž“αž·αž„αž”αž„αŸ’αž€αžΎαž StreamWriter:

sink = pa.InMemoryOutputStream()
stream_writer = pa.StreamWriter(sink, batch.schema)

αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€αž™αžΎαž„αž“αžΉαž„αžŸαžšαžŸαŸαžš 1024 αž€αŸ†αžŽαžΆαžαŸ‹ αžŠαŸ‚αž›αž“αŸ…αž‘αžΈαž”αŸ†αž•αž»αžαž“αžΉαž„αž”αž„αŸ’αž€αžΎαžαžŸαŸ†αžŽαž»αŸ†αž‘αž·αž“αŸ’αž“αž“αŸαž™ 1GBαŸ–

for i in range(DATA_SIZE // MEGABYTE):
    stream_writer.write_batch(batch)

αž…αžΆαž”αŸ‹αžαžΆαŸ†αž„αž–αžΈαž™αžΎαž„αžŸαžšαžŸαŸαžšαž‘αŸ… RAM αž™αžΎαž„αž’αžΆαž…αž‘αž‘αž½αž›αž”αžΆαž“αž…αžšαž“αŸ’αžαž‘αžΆαŸ†αž„αž˜αžΌαž›αž“αŸ…αž€αŸ’αž“αž»αž„αžŸαžαž·αž”αžŽαŸ’αžŠαŸ„αŸ‡αž’αžΆαžŸαž“αŸ’αž“αžαŸ‚αž˜αž½αž™αŸ–

In [13]: source = sink.get_result()

In [14]: source
Out[14]: <pyarrow.io.Buffer at 0x7f2df7118f80>

In [15]: source.size
Out[15]: 1074750744

αžŠαŸ„αž™αžŸαžΆαžšαž‘αž·αž“αŸ’αž“αž“αŸαž™αž“αŸαŸ‡αžŸαŸ’αžαž·αžαž“αŸ…αž€αŸ’αž“αž»αž„αž’αž„αŸ’αž‚αž…αž„αž…αžΆαŸ† αž€αžΆαžšαž’αžΆαž“αž”αžŽαŸ’αžαž»αŸ†αž“αŸƒαž€αŸ†αžŽαžαŸ‹αžαŸ’αžšαžΆαž–αŸ’αžšαž½αž‰αž‚αžΊαž‡αžΆαž”αŸ’αžšαžαž·αž”αžαŸ’αžαž·αž€αžΆαžšαž…αž˜αŸ’αž›αž„αžŸαžΌαž“αŸ’αž™αŸ” αžαŸ’αž‰αž»αŸ†αž”αžΎαž€ StreamReader αž’αžΆαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™αž…αžΌαž› pyarrow.Tableαž αžΎαž™αž”αž“αŸ’αž‘αžΆαž”αŸ‹αž˜αž€αž”αŸ†αž”αŸ’αž›αŸ‚αž„αž–αž½αž€αžœαžΆαž‘αŸ…αž‡αžΆ DataFrame pandas:

In [16]: reader = pa.StreamReader(source)

In [17]: table = reader.read_all()

In [18]: table
Out[18]: <pyarrow.table.Table at 0x7fae8281f6f0>

In [19]: df = table.to_pandas()

In [20]: df.memory_usage().sum()
Out[20]: 1073741904

αž‘αžΆαŸ†αž„αž’αžŸαŸ‹αž“αŸαŸ‡αž–αž·αžαžŽαžΆαžŸαŸ‹αž‚αžΊαž›αŸ’αž’ αž”αŸ‰αž»αž“αŸ’αžαŸ‚αž’αŸ’αž“αž€αž’αžΆαž…αž˜αžΆαž“αžŸαŸ†αžŽαž½αžšαŸ” αžαžΎαžšαžΏαž„αž“αŸαŸ‡αž€αžΎαžαž‘αžΎαž„αž›αžΏαž“αž”αŸ‰αž»αžŽαŸ’αžŽαžΆ? αžαžΎαž‘αŸ†αž αŸ†αž€αŸ†αžŽαžΆαžαŸ‹αž”αŸ‰αŸ‡αž–αžΆαž›αŸ‹αžŠαž›αŸ‹αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž‘αžΆαž‰αž™αž€ DataFrame αžšαž”αžŸαŸ‹αž•αŸαž“αžŠαžΆαž™αŸ‰αžΆαž„αžŠαžΌαž…αž˜αŸ’αžαŸαž…?

αž€αžΆαžšαžŸαž˜αŸ’αžαŸ‚αž„αžŸαŸ’αž‘αŸ’αžšαžΈαž˜

αž“αŸ…αž–αŸαž›αžŠαŸ‚αž›αž‘αŸ†αž αŸ†αž€αŸ†αžŽαžΆαžαŸ‹αžŸαŸ’αž‘αŸ’αžšαžΈαž˜αž˜αžΆαž“αž€αžΆαžšαžαž™αž…αž»αŸ‡ αž€αžΆαžšαž…αŸ†αžŽαžΆαž™αž“αŸƒαž€αžΆαžšαž”αž„αŸ’αž€αžΎαž DataFrame αž‡αž½αžšαžˆαžšαž‡αžΆαž”αŸ‹αž‚αŸ’αž“αžΆαž“αŸ…αž€αŸ’αž“αž»αž„αž•αŸαž“αžŠαžΆαž€αžΎαž“αž‘αžΎαž„ αžŠαŸ„αž™αžŸαžΆαžšαž›αŸ†αž“αžΆαŸ†αž…αžΌαž›αž”αŸ’αžšαžΎαžƒαŸ’αž›αžΆαŸ†αž„αžŸαž˜αŸ’αž„αžΆαžαŸ‹αž˜αž·αž“αž˜αžΆαž“αž”αŸ’αžšαžŸαž·αž‘αŸ’αž’αž—αžΆαž–αŸ” αžœαžΆαž€αŸαž˜αžΆαž“αž€αžΆαžšαž…αŸ†αžŽαžΆαž™αž›αžΎαžŸαž˜αž½αž™αž…αŸ†αž“αž½αž“αž–αžΈαž€αžΆαžšαž’αŸ’αžœαžΎαž€αžΆαžšαž‡αžΆαž˜αž½αž™αžšαž…αž“αžΆαžŸαž˜αŸ’αž–αŸαž“αŸ’αž’αž‘αž·αž“αŸ’αž“αž“αŸαž™ C ++ αž“αž·αž„αž’αžΆαžšαŸ αž“αž·αž„αž’αž„αŸ’αž‚αž…αž„αž…αžΆαŸ†αž”αžŽαŸ’αžαŸ„αŸ‡αž’αžΆαžŸαž“αŸ’αž“αžšαž”αžŸαŸ‹αž–αž½αž€αž‚αŸαŸ”

αžŸαž˜αŸ’αžšαžΆαž”αŸ‹ 1 MB αžŠαžΌαž…αžαžΆαž„αž›αžΎαž“αŸ…αž›αžΎαž€αž»αŸ†αž–αŸ’αž™αžΌαž‘αŸαžšαž™αž½αžšαžŠαŸƒαžšαž”αžŸαŸ‹αžαŸ’αž‰αž»αŸ† (Quad-core Xeon E3-1505M) αžœαžΆαž”αŸ’αžšαŸ‚αžαžΆ:

In [20]: %timeit pa.StreamReader(source).read_all().to_pandas()
10 loops, best of 3: 129 ms per loop

αžœαžΆαž”αŸ’αžšαŸ‚αžαžΆαž›αŸ†αž αžΌαžšαžŠαŸ‚αž›αž˜αžΆαž“αž”αŸ’αžšαžŸαž·αž‘αŸ’αž’αž—αžΆαž–αž‚αžΊ 7.75 GB/s αžŠαžΎαž˜αŸ’αž”αžΈαžŸαŸ’αžŠαžΆαžš DataFrame 1GB αž–αžΈ 1024 1MB αž€αŸ†αžŽαžΆαžαŸ‹αŸ” αžαžΎαž˜αžΆαž“αž’αŸ’αžœαžΈαž€αžΎαžαž‘αžΎαž„αž”αŸ’αžšαžŸαž·αž“αž”αžΎαž™αžΎαž„αž”αŸ’αžšαžΎαž€αŸ†αžŽαžΆαžαŸ‹αž’αŸ†αž‡αžΆαž„αž¬αžαžΌαž…αž‡αžΆαž„? αž‘αžΆαŸ†αž„αž“αŸαŸ‡αž‚αžΊαž‡αžΆαž›αž‘αŸ’αž’αž•αž›αŸ–

αžŸαŸ’αž‘αŸ’αžšαžΈαž˜αž‘αž·αž“αŸ’αž“αž“αŸαž™αž‡αž½αžšαžˆαžšαž‡αžΆαž˜αž½αž™ Apache Arrow

αž€αžΆαžšαžŸαž˜αŸ’αžαŸ‚αž„αž’αŸ’αž›αžΆαž€αŸ‹αž…αž»αŸ‡αž™αŸ‰αžΆαž„αžαŸ’αž›αžΆαŸ†αž„αž–αžΈ 256K αž‘αŸ… 64K αž€αŸ†αžŽαžΆαžαŸ‹αŸ” αžαŸ’αž‰αž»αŸ†αž—αŸ’αž‰αžΆαž€αŸ‹αž•αŸ’αž’αžΎαž›αžŠαŸ‚αž›αž€αŸ†αžŽαžΆαžαŸ‹ 1 MB αžαŸ’αžšαžΌαžœαž”αžΆαž“αžŠαŸ†αžŽαžΎαžšαž€αžΆαžšαž›αžΏαž“αž‡αžΆαž„αž€αŸ†αžŽαžΆαžαŸ‹ 16 MB αŸ” αžœαžΆαž˜αžΆαž“αžαž˜αŸ’αž›αŸƒαž’αŸ’αžœαžΎαž€αžΆαžšαžŸαž·αž€αŸ’αžŸαžΆ αž“αž·αž„αžŸαŸ’αžœαŸ‚αž„αž™αž›αŸ‹αž±αŸ’αž™αž”αžΆαž“αž αŸ’αž˜αžαŸ‹αž…αžαŸ‹αž”αž“αŸ’αžαŸ‚αž˜αž‘αŸ€αžαžαžΆαžαžΎαž“αŸαŸ‡αž‚αžΊαž‡αžΆαž€αžΆαžšαž…αŸ‚αž€αž…αžΆαž™αž’αž˜αŸ’αž˜αžαžΆαž¬αžαžΆαžαžΎαž˜αžΆαž“αž’αŸ’αžœαžΈαž•αŸ’αžŸαŸαž„αž‘αŸ€αžαž“αŸ…αž€αŸ’αž“αž»αž„αž€αžΆαžšαž›αŸαž„αŸ”

αž“αŸ…αž€αŸ’αž“αž»αž„αž€αžΆαžšαž’αž“αž»αžœαžαŸ’αžαž”αž…αŸ’αž…αž»αž”αŸ’αž”αž“αŸ’αž“αž“αŸƒαž‘αŸ’αžšαž„αŸ‹αž‘αŸ’αžšαžΆαž™ αž‘αž·αž“αŸ’αž“αž“αŸαž™αž˜αž·αž“αžαŸ’αžšαžΌαžœαž”αžΆαž“αž”αž„αŸ’αž αžΆαž”αŸ‹αž‡αžΆαž‚αŸ„αž›αž€αžΆαžšαžŽαŸαž‘αŸ αžŠαžΌαž…αŸ’αž“αŸαŸ‡αž‘αŸ†αž αŸ†αž“αŸ…αž€αŸ’αž“αž»αž„αž’αž„αŸ’αž‚αž…αž„αž…αžΆαŸ† αž“αž·αž„ "αž“αŸ…αž€αŸ’αž“αž»αž„αžαŸ’αžŸαŸ‚" αž‚αžΊαž”αŸ’αžšαž αŸ‚αž›αžŠαžΌαž…αž‚αŸ’αž“αžΆαŸ” αž“αŸ…αž–αŸαž›αž’αž“αžΆαž‚αž αž€αžΆαžšαž”αž„αŸ’αž αžΆαž”αŸ‹αž’αžΆαž…αž€αŸ’αž›αžΆαž™αž‡αžΆαž‡αž˜αŸ’αžšαžΎαžŸαž”αž“αŸ’αžαŸ‚αž˜αŸ”

αž›αž‘αŸ’αž’αž•αž›

αž€αžΆαžšαžŸαŸ’αž‘αŸ’αžšαžΈαž˜αž‘αž·αž“αŸ’αž“αž“αŸαž™αž‡αž½αžšαžˆαžšαž’αžΆαž…αž‡αžΆαž˜αž’αŸ’αž™αŸ„αž”αžΆαž™αžŠαŸαž˜αžΆαž“αž”αŸ’αžšαžŸαž·αž‘αŸ’αž’αž—αžΆαž–αž˜αž½αž™αžŠαžΎαž˜αŸ’αž”αžΈαž”αž‰αŸ’αž…αžΌαž›αžŸαŸ†αžŽαž»αŸ†αž‘αž·αž“αŸ’αž“αž“αŸαž™αž’αŸ†αž‘αŸ…αž€αŸ’αž“αž»αž„αž§αž”αž€αžšαžŽαŸαžœαž·αž—αžΆαž‚αž‡αž½αžšαžˆαžšαžŠαžΌαž…αž‡αžΆαžαŸ’αž›αžΆαžƒαŸ’αž˜αž»αŸ†αž•αŸαž“αžŠαžΆαž€αŸ’αž“αž»αž„αž•αŸ’αž“αŸ‚αž€αžαžΌαž…αŸ—αŸ” αžŸαŸαžœαžΆαž€αž˜αŸ’αž˜αž‘αž·αž“αŸ’αž“αž“αŸαž™αžŠαŸ‚αž›αž”αŸ’αžšαžΎαž€αžΆαžšαž•αŸ’αž‘αž»αž€αžαž˜αŸ’αžšαž„αŸ‹αž‡αž½αžšαž’αžΆαž…αž•αŸ’αž‘αŸαžš αž“αž·αž„αž”αž‰αŸ’αž‡αžΌαž“αž‘αž·αž“αŸ’αž“αž“αŸαž™αžαžΌαž…αŸ—αžŠαŸ‚αž›αž„αžΆαž™αžŸαŸ’αžšαž½αž›αž‡αžΆαž„αžŸαž˜αŸ’αžšαžΆαž”αŸ‹αžƒαŸ’αž›αžΆαŸ†αž„αžŸαž˜αŸ’αž„αžΆαžαŸ‹ L2 αž“αž·αž„ L3 αžšαž”αžŸαŸ‹αžαž½αžšαž€αŸ’αž”αžΆαž›αž’αŸ’αž“αž€αŸ”

αž›αŸαžαž€αžΌαžŠαž–αŸαž‰

import time
import numpy as np
import pandas as pd
import pyarrow as pa

def generate_data(total_size, ncols):
    nrows = total_size / ncols / np.dtype('float64').itemsize
    return pd.DataFrame({
        'c' + str(i): np.random.randn(nrows)
        for i in range(ncols)
    })

KILOBYTE = 1 << 10
MEGABYTE = KILOBYTE * KILOBYTE
DATA_SIZE = 1024 * MEGABYTE
NCOLS = 16

def get_timing(f, niter):
    start = time.clock_gettime(time.CLOCK_REALTIME)
    for i in range(niter):
        f()
    return (time.clock_gettime(time.CLOCK_REALTIME) - start) / NITER

def read_as_dataframe(klass, source):
    reader = klass(source)
    table = reader.read_all()
    return table.to_pandas()
NITER = 5
results = []

CHUNKSIZES = [16 * KILOBYTE, 64 * KILOBYTE, 256 * KILOBYTE, MEGABYTE, 16 * MEGABYTE]

for chunksize in CHUNKSIZES:
    nchunks = DATA_SIZE // chunksize
    batch = pa.RecordBatch.from_pandas(generate_data(chunksize, NCOLS))

    sink = pa.InMemoryOutputStream()
    stream_writer = pa.StreamWriter(sink, batch.schema)

    for i in range(nchunks):
        stream_writer.write_batch(batch)

    source = sink.get_result()

    elapsed = get_timing(lambda: read_as_dataframe(pa.StreamReader, source), NITER)

    result = (chunksize, elapsed)
    print(result)
    results.append(result)

αž”αŸ’αžšαž—αž–: www.habr.com

αž”αž“αŸ’αžαŸ‚αž˜αž˜αžαž·αž™αŸ„αž”αž›αŸ‹