Pandas: read_csv () в 3,5 раза медленнее в Pandas 0.23.4 на Python 3.7.1 по сравнению с Pandas 0.22.0 на Python 3.5.2

Созданный на 5 нояб. 2018  ·  56Комментарии  ·  Источник: pandas-dev/pandas

Пример кода, копируемый пример, если возможно

import io
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randn(1000000, 10), columns=('COL{}'.format(i) for i in range(10)))
csv = io.StringIO(df.to_csv(index=False))
df2 = pd.read_csv(csv)

Описание проблемы

pd.read_csv() с использованием метода _libs.parsers.TextReader read() работает в 3,5 раза медленнее на Pandas 0.23.4 на Python 3.7.1 по сравнению с Pandas 0.22.0 на Python 3.5.2.

 4244 function calls (4210 primitive calls) in 10.273 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1   10.202   10.202   10.204   10.204 {method 'read' of 'pandas._libs.parsers.TextReader' objects}
        1    0.039    0.039    0.039    0.039 internals.py:5017(_stack_arrays)
        1    0.011    0.011   10.262   10.262 parsers.py:414(_read)
        1    0.011    0.011   10.273   10.273 <string>:1(<module>)
        1    0.004    0.004    0.004    0.004 parsers.py:1685(__init__)
      321    0.001    0.000    0.002    0.000 common.py:811(is_integer_dtype)

Ожидаемый результат

3229 function calls (3222 primitive calls) in 2.944 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    2.881    2.881    2.882    2.882 {method 'read' of 'pandas._libs.parsers.TextReader' objects}
        1    0.045    0.045    0.045    0.045 internals.py:4801(_stack_arrays)
        1    0.010    0.010    2.944    2.944 parsers.py:423(_read)
        1    0.004    0.004    0.004    0.004 parsers.py:1677(__init__)
      320    0.001    0.000    0.001    0.000 common.py:777(is_integer_dtype)
        1    0.001    0.001    0.001    0.001 {method 'close' of 'pandas._libs.p

Выход pd.show_versions() -- Latst Python 3.7.1 Pandas 0.23.4 : Slow Read CSV

УСТАНОВЛЕННЫЕ ВЕРСИИ

фиксация: Нет
питон: 3.7.1.final.0
биты Python: 64
ОС: Windows
Выпуск ОС: 2008 ServerR2
машина: AMD64
процессор: Intel64 Family 6 Model 63 Stepping 2, GenuineIntel
byteorder: маленький
LC_ALL: Нет
ЯЗЫК: Нет
МЕСТО: Нет.

панды: 0.23.4
pytest: 3.9.2
пункт: 18,1
setuptools: 40.4.3
Cython: 0,29
число: 1.15.3
scipy: 1.1.0
Pyarrow: 0.11.0
xarray: 0.10.9
IPython: 7.0.1
сфинкс: 1.8.1
Пэтси: 0.5.0
dateutil: 2.7.3
pytz: 2018.5
blosc: 1.6.1
узкое место: 1.2.1
таблицы: 3.4.4
numexpr: 2.6.8
перо: Нет
matplotlib: 3.0.0
openpyxl: 2.5.9
xlrd: 1.1.0
xlwt: 1.3.0
xlsxwriter: Нет
лхмл: 4.2.5
BS4: 4.6.3
html5lib: 1.0.1
sqlalchemy: 1.2.12
pymysql: Нет
psycopg2: Нет
jinja2: 2.10
s3fs: Нет
fastparquet: 0.1.6
pandas_gbq: Нет
pandas_datareader: Нет

Вывод pd.show_versions() -- Older Python 3.5.2 Pandas 0.22.0 : Fast Read CSV

УСТАНОВЛЕННЫЕ ВЕРСИИ

фиксация: Нет
питон: 3.5.2.final.0
биты Python: 64
ОС: Windows
ОС-релиз: 7
машина: AMD64
процессор: Intel64 Family 6 Model 63 Stepping 2, GenuineIntel
byteorder: маленький
LC_ALL: Нет
ЯЗЫК: Нет
МЕСТО: Нет.

панды: 0.22.0
pytest: 3.5.0
пункт: 9.0.3
setuptools: 20.10.1
Cython: 0.28.1
число: 1.14.2
scipy: 1.0.1
пиарроу: 0.9.0
xarray: 0.10.2
IPython: 6.3.0
сфинкс: 1.7.2
Пэтси: 0.5.0
dateutil: 2.7.2
pytz: 2018.3
blosc: Нет
узкое место: 1.2.1
таблицы: 3.4.2
numexpr: 2.6.4
перо: 0,4,0
matplotlib: 2.2.2
openpyxl: 2.5.1
xlrd: 1.1.0
xlwt: 1.3.0
xlsxwriter: Нет
лхмл: 4.2.1
BS4: 4.6.0
html5lib: 0,9999999
sqlalchemy: 1.2.6
pymysql: Нет
psycopg2: Нет
jinja2: 2.10
s3fs: Нет
fastparquet: 0.1.5
pandas_gbq: Нет
pandas_datareader: Нет

IO CSV Performance

Самый полезный комментарий

Я сравнил инструкцию df2 = pd.read_csv(csv) на Python 3.7.0a3 и a4 в профилировщике Visual Studio. Виновником является функция isdigit вызываемая в модуле расширения parsers . На 3.7.0a3 функция работает быстро на ~ 8% выборок. На 3.7.0a4 функция работает медленно на ~ 64% выборок, потому что она вызывает функцию _isdigit_l , которая, кажется, обновляет и восстанавливает языковой стандарт в текущем потоке каждый раз ...

3.7.0a3:
Function Name   Inclusive Samples   Exclusive Samples   Inclusive Samples % Exclusive Samples % Module Name
 + [parsers.cp37-win_amd64.pyd] 705 347 28.52%  14.04%  parsers.cp37-win_amd64.pyd
   isdigit  207 207 8.37%   8.37%   ucrtbase.dll
 - _errno   105 39  4.25%   1.58%   ucrtbase.dll
   toupper  24  24  0.97%   0.97%   ucrtbase.dll
   isspace  21  21  0.85%   0.85%   ucrtbase.dll
   [python37.dll]   1   1   0.04%   0.04%   python37.dll
3.7.0a4:
Function Name   Inclusive Samples   Exclusive Samples   Inclusive Samples % Exclusive Samples % Module Name
 + [parsers.cp37-win_amd64.pyd] 8,613   478 83.04%  4.61%   parsers.cp37-win_amd64.pyd
 + isdigit  6,642   208 64.04%  2.01%   ucrtbase.dll
 + _isdigit_l   6,434   245 62.03%  2.36%   ucrtbase.dll
 + _LocaleUpdate::_LocaleUpdate 5,806   947 55.98%  9.13%   ucrtbase.dll
 + __acrt_getptd    2,121   1,031   20.45%  9.94%   ucrtbase.dll
   FlsGetValue  647 647 6.24%   6.24%   KernelBase.dll
 - RtlSetLastWin32Error 296 235 2.85%   2.27%   ntdll.dll
   _guard_dispatch_icall_nop    101 101 0.97%   0.97%   ucrtbase.dll
   GetLastError 46  46  0.44%   0.44%   KernelBase.dll
 + __acrt_update_multibyte_info 1,475   246 14.22%  2.37%   ucrtbase.dll
 - __crt_state_management::get_current_state_index  1,229   513 11.85%  4.95%   ucrtbase.dll
 + __acrt_update_locale_info    1,263   235 12.18%  2.27%   ucrtbase.dll
 - __crt_state_management::get_current_state_index  1,028   429 9.91%   4.14%   ucrtbase.dll
   _ischartype_l    383 383 3.69%   3.69%   ucrtbase.dll

Все 56 Комментарий

Можете ли вы сравнить только изменение в Python и только изменение в пандах по отдельности?

Можете ли вы сравнить только изменение в Python и только изменение в пандах по отдельности?

Да, есть ли более старые сборки Pandas на Python 3.7.1? Полагаю, я могу попробовать более новую версию pandas на старом Python.

Я думаю, что 0.23.2 - первая версия панд с поддержкой 3.7.

В понедельник, 5 ноября 2018 г., в 13:15 Gagi [email protected] написал:

Можете ли вы сравнить только изменение в python и только изменение в пандах
раздельно?

Да, есть ли более старые сборки Pandas на Python 3.7.1? Полагаю, я могу попробовать
более новая версия pandas на старом Python.

-
Вы получили это, потому что прокомментировали.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/pandas-dev/pandas/issues/23516#issuecomment-435999395 ,
или отключить поток
https://github.com/notifications/unsubscribe-auth/ABQHIm27-U5HB6S2JcM2DPtr6YzlPC90ks5usI48gaJpZM4YPD2Y
.

Я провел тест на более старом стеке Python 3.5 с последней версией Pandas 0.23.4, но с множеством более старых версий других модулей, и похоже, что он работает быстрее на Python 3.5. Я не совсем уверен, связаны ли его панды непосредственно с python 3.7.1 или с одной из его зависимостей.

Метод парсера _read() полагается на какую-то другую библиотеку, которая может быть виновником?

 %prun df2 = pd.read_csv(csv)
         5154 function calls (5041 primitive calls) in 2.004 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    1.960    1.960    1.962    1.962 {method 'read' of 'pandas._libs.parsers.TextReader' objects}
        1    0.030    0.030    0.030    0.030 internals.py:5017(_stack_arrays)
        1    0.006    0.006    2.004    2.004 parsers.py:414(_read)
        1    0.003    0.003    0.003    0.003 parsers.py:1685(__init__)
      321    0.001    0.000    0.001    0.000 common.py:811(is_integer_dtype)
      518    0.000    0.000    0.000    0.000 common.py:1835(_get_dtype_type)

Установлен стек Python 3.5 с последними пандами 0.23.4:

УСТАНОВЛЕННЫЕ ВЕРСИИ

фиксация: Нет
питон: 3.5.2.final.0
биты Python: 64
ОС: Windows
ОС-релиз: 10
машина: AMD64
процессор: Intel64 Family 6 Model 158 Stepping 10, GenuineIntel
byteorder: маленький
LC_ALL: Нет
ЯЗЫК: Нет
МЕСТО: Нет.

панды: 0.23.4
pytest: 3.5.0
пункт: 18.0
setuptools: 38.6.0
Cython: 0.28.1
число: 1.14.2
scipy: 1.0.1
пиарроу: 0.10.0
xarray: 0.10.2
IPython: 6.3.0
сфинкс: 1.7.2
Пэтси: 0.5.0
dateutil: 2.7.2
pytz: 2018.3
blosc: 1.5.1
узкое место: 1.2.1
таблицы: 3.4.2
numexpr: 2.6.4
перо: 0,4,0
matplotlib: 2.2.2
openpyxl: 2.5.1
xlrd: 1.1.0
xlwt: 1.3.0
xlsxwriter: Нет
лхмл: 4.2.1
BS4: 4.6.0
html5lib: 0,9999999
sqlalchemy: 1.2.6
pymysql: Нет
psycopg2: Нет
jinja2: 2.10
s3fs: Нет
fastparquet: 0.1.5
pandas_gbq: Нет
pandas_datareader: Нет

<\ подробности>

Интересно, что если я укажу float_precision='round_trip' я получу аналогичные скорости синтаксического анализа. Если я укажу «высокий» или «Нет», то вернемся к той же разнице в 3,5 раза.

__Python 3.7.1__

 %prun df2 = pd.read_csv(csv, float_precision='round_trip')
         4320 function calls (4286 primitive calls) in 4.074 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    3.862    3.862    3.864    3.864 {method 'read' of 'pandas._libs.parsers.TextReader' objects}
        1    0.168    0.168    4.074    4.074 <string>:1(<module>)
        1    0.030    0.030    0.030    0.030 internals.py:5017(_stack_arrays)
        1    0.006    0.006    3.906    3.906 parsers.py:414(_read)
        1    0.003    0.003    0.003    0.003 parsers.py:1685(__init__)
      321    0.001    0.000    0.002    0.000 common.py:811(is_integer_dtype)
      516    0.000    0.000    0.001    0.000 common.py:1835(_get_dtype_type)
      952    0.000    0.000    0.000    0.000 {built-in method builtins.isinstance}

__Python 3.5.2__

 %prun df2 = pd.read_csv(csv, float_precision='round_trip')
         4582 function calls (4545 primitive calls) in 3.716 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    3.665    3.665    3.667    3.667 {method 'read' of 'pandas._libs.parsers.TextReader' objects}
        1    0.031    0.031    0.031    0.031 internals.py:5017(_stack_arrays)
        1    0.006    0.006    3.710    3.710 parsers.py:414(_read)
        1    0.006    0.006    3.716    3.716 <string>:1(<module>)
        1    0.003    0.003    0.003    0.003 parsers.py:1685(__init__)
      321    0.001    0.000    0.001    0.000 common.py:811(is_integer_dtype)
      518    0.000    0.000    0.001    0.000 common.py:1835(_get_dtype_type)

Добавление еще одной точки данных. Если я укажу движок python. Похоже, что на Python 3.7.1 pandas._libs.lib.maybe_convert_numeric в 3 раза медленнее, чем на Python на 3.5.2

Может ли это быть из-за версии cython?

__Python 3.7.1__

%prun df2 = pd.read_csv(csv, engine='python')
         7003613 function calls (7003575 primitive calls) in 14.411 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
       10    9.698    0.970    9.698    0.970 {pandas._libs.lib.maybe_convert_numeric}
  1000004    3.221    0.000    3.221    0.000 {built-in method builtins.next}
        1    0.386    0.386    4.066    4.066 parsers.py:2926(_get_lines)
        1    0.263    0.263   14.399   14.399 parsers.py:1029(read)
        4    0.154    0.038    0.247    0.062 parsers.py:2738(_remove_empty_lines)
  1000002    0.138    0.000    3.359    0.000 parsers.py:2681(_next_iter_line)
  2000072    0.125    0.000    0.125    0.000 {method 'append' of 'list' objects}
        1    0.116    0.116    0.116    0.116 {pandas._libs.lib.to_object_array}
  1000001    0.103    0.000    0.138    0.000 parsers.py:2869(<genexpr>)
2000130/2000117    0.069    0.000    0.069    0.000 {built-in method builtins.len}
       14    0.067    0.005    0.204    0.015 {built-in method builtins.max}

__Python 3.5.2__

 %prun df2 = pd.read_csv(csv, engine='python')
         7004040 function calls (7004000 primitive calls) in 8.411 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  1000003    3.662    0.000    3.662    0.000 {built-in method builtins.next}
       10    3.270    0.327    3.270    0.327 {pandas._libs.lib.maybe_convert_numeric}
        1    0.378    0.378    4.492    4.492 parsers.py:2926(_get_lines)
        1    0.263    0.263    8.398    8.398 parsers.py:1029(read)
        4    0.167    0.042    0.245    0.061 parsers.py:2738(_remove_empty_lines)
  1000002    0.141    0.000    3.803    0.000 parsers.py:2681(_next_iter_line)
        1    0.128    0.128    0.128    0.128 {pandas._libs.lib.to_object_array}
  2000067    0.109    0.000    0.109    0.000 {method 'append' of 'list' objects}
  1000001    0.108    0.000    0.133    0.000 parsers.py:2869(<genexpr>)
       14    0.060    0.004    0.193    0.014 {built-in method builtins.max}

Эти последние числа относятся к какой версии панд?

Эти последние числа относятся к какой версии панд?

Они обе Панды 0.23.4

Я попытался собрать последнюю версию Pandas из исходного кода на Python 3.7.1, но все равно получил такую ​​же более низкую производительность. Есть ли какие-либо флаги сборки / компиляции / cython, которые я могу установить для оптимизации синтаксического анализатора?

вся проблема с перфомансом - это просто флаг точности

вы можете выбрать более высокую точность, но это займет больше времени; это редко бывает полезно

вся проблема с перфомансом - это просто флаг точности

вы можете выбрать более высокую точность, но это займет больше времени; это редко бывает полезно

Я пробовал все три разных флага float_precision= и для «высокого» и «Ни одного» замедление в 3,5 раза все еще присутствовало в Python 3.7.1 по сравнению с python 2.5.2.

Я также попытался указать float_format= в pd.to_csv (), и я все еще вижу тот же последовательный разрыв в 3,5 раза.

Можете ли вы воспроизвести в Python 3.6?

Я должен повторить, что разница в производительности есть в одной и той же версии Pandas 0.23.4, просто в другой версии Python.

есть ли способ указать 'xstrtod', или это указано в float_precision = None?

Я не вижу изменений производительности между «High» и «None».

Кто-нибудь может воспроизвести это на Python 3.7.1? Я протестировал приведенный выше код на Python 3.7.0 с помощью интерактивного интерпретатора Python.org, и, похоже, он работал быстрее, чем в моей локальной установке 3.7.1.

Что-то определенно не так. Я провел параллельное сравнение чтения одного и того же файла CSV на диске. Python 3.5 читает со скоростью 111 МБ / с, а Python 3.7 читает только 28 МБ / с с того же SSD. Оба работают под управлением Pandas 0.23.4.

Мог ли Python 3.7 что-то изменить в их системе ввода-вывода?

__Python 3.5.2 и Pandas 0.23.4__

In [38]: %timeit pd.read_csv(r'out.csv', float_precision='high')
1.86 s ± 13.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

__Python 3.7.1 и Pandas 0.23.4__

In [17]: %timeit pd.read_csv(r'out.csv', float_precision='high')
7.97 s ± 19 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

image

Я не вижу разницы, которую ты видишь

Python 3.5.6 |Anaconda, Inc.| (default, Aug 26 2018, 16:30:03)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.5.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import pandas as pd

In [2]: pd.__version__
Out[2]: '0.23.4'

In [3]: %time _ = pd.read_csv('out.csv', float_precision='high')
CPU times: user 2.59 s, sys: 214 ms, total: 2.81 s
Wall time: 2.73 s

3,7

Python 3.7.1 (default, Oct 23 2018, 14:07:42)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.1.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import pandas as pd

In [2]: pd.__version__
Out[2]: '0.23.4'

In [3]: %time _ = pd.read_csv('out.csv', float_precision='high')
CPU times: user 2.61 s, sys: 211 ms, total: 2.82 s
Wall time: 2.74 s

Оба они используют пакеты Anaconda.

Том, спасибо за выполнение этого теста. Не могли бы вы опубликовать свой pd.show_versions (). Я хочу воссоздать ваш стек именно для того, чтобы провести еще какое-то тестирование.

3.5

INSTALLED VERSIONS
------------------
commit: None
python: 3.5.6.final.0
python-bits: 64
OS: Darwin
OS-release: 17.7.0
machine: x86_64
processor: i386
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8
LOCALE: en_US.UTF-8

pandas: 0.23.4
pytest: None
pip: 10.0.1
setuptools: 40.2.0
Cython: None
numpy: 1.15.2
scipy: None
pyarrow: None
xarray: None
IPython: 6.5.0
sphinx: None
patsy: None
dateutil: 2.7.3
pytz: 2018.5
blosc: None
bottleneck: None
tables: None
numexpr: None
feather: None
matplotlib: None
openpyxl: None
xlrd: None
xlwt: None
xlsxwriter: None
lxml: None
bs4: None
html5lib: None
sqlalchemy: None
pymysql: None
psycopg2: None
jinja2: None
s3fs: None
fastparquet: None
pandas_gbq: None
pandas_datareader: None

3.7:

INSTALLED VERSIONS
------------------
commit: None
python: 3.7.1.final.0
python-bits: 64
OS: Darwin
OS-release: 17.7.0
machine: x86_64
processor: i386
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8
LOCALE: en_US.UTF-8

pandas: 0.23.4
pytest: None
pip: 18.1
setuptools: 40.5.0
Cython: None
numpy: 1.15.4
scipy: None
pyarrow: None
xarray: None
IPython: 7.1.1
sphinx: None
patsy: None
dateutil: 2.7.5
pytz: 2018.7
blosc: None
bottleneck: None
tables: None
numexpr: None
feather: None
matplotlib: None
openpyxl: None
xlrd: None
xlwt: None
xlsxwriter: None
lxml: None
bs4: None
html5lib: None
sqlalchemy: None
pymysql: None
psycopg2: None
jinja2: None
s3fs: None
fastparquet: None
pandas_gbq: None
pandas_datareader: None

Я пробовал несколько разных свежих установок Python в Windows. Каждая 32- или 64-разрядная установка Python 3.7 с установленным пакетом Pandas 0.23.4 приводит к снижению скорости синтаксического анализа CSV. Ради интереса я попытался установить новую установку Python 3.6.7, и она снова анализирует тот же CSV в 3 раза быстрее.

Есть ли кто-нибудь, кто мог бы протестировать это на Windows 10 и Python 3.7.1? 😕

cc @ chris-b1 на случай, если вы можете протестировать в Windows

Действительно, я могу подтвердить, что при использовании Python 3.7.1 в Windows 10 наблюдается замедление в 3,5 раза.

Когда я использую Python 3.5.6, производительность не меняется с 0.22.0 до 0.23.4 .

Эти наблюдения согласуются с тем, что наблюдал @dragoljub, и, похоже, предполагают, что это предложение Cython / Python, а не pandas .

В windows 10, python 3.6 и python 3.7 я также заметил заметное замедление.

(py36) PS C:\Users\ttttt> ipython
Python 3.6.4 | packaged by conda-forge | (default, Dec 24 2017, 10:11:43) [MSC v.1900 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 7.1.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import pandas as pd

In [2]: %time _ = pd.read_csv('out.csv', float_precision='high')
Wall time: 7.03 s

In [3]: %time _ = pd.read_csv('out.csv')
Wall time: 7.04 s

Python 3.7

`` питон
(py37) PS C: \ Users \ ttttt> ipython
Python 3.7.1 (по умолчанию, 28 октября 2018 г., 08:39:03) [MSC v.1912, 64-разрядная версия (AMD64)]
Введите "авторское право", "кредиты" или "лицензия" для получения дополнительной информации.
IPython 7.1.1 - усовершенствованный интерактивный Python. Тип '?' за помощью.

В [1]: импортировать панды как pd
В [2]: df = pd.DataFrame (np.random.randn (1000000, 10), columns = ('COL {}'. Format (i) for i in range (10)))
В [6]: df.to_csv ('out.csv')
В [7]:% time _ = pd.read_csv ('out.csv', float_precision = 'high')
Время стены: 29,4 с

В [8]:% time _ = pd.read_csv ('out.csv')
Время стены: 31,3 с
`` ''

Для людей на windows, как вы устанавливаете панды? Из исходников, колес или пакетов conda? А если конда, то от дефолта или от конда-форжа?

Вот конда-кузница:

PS C:\Users\ttttt> activate py37
(py37) PS C:\Users\ttttt> conda install ipython pandas
Solving environment: done
## Package Plan ##
  environment location: C:\Miniconda\envs\py37
  added / updated specs:
    - ipython
    - pandas
The following packages will be downloaded:
    package                    |            build
    ---------------------------|-----------------
    ipython-7.1.1              |py37h39e3cac_1000         1.1 MB  conda-forge
    wcwidth-0.1.7              |             py_1          17 KB  conda-forge
    six-1.11.0                 |        py37_1001          21 KB  conda-forge
    pytz-2018.7                |             py_0         226 KB  conda-forge
    icc_rt-2017.0.4            |       h97af966_0         8.0 MB
    pygments-2.2.0             |             py_1         622 KB  conda-forge
    pickleshare-0.7.5          |        py37_1000          12 KB  conda-forge
    certifi-2018.10.15         |        py37_1000         137 KB  conda-forge
    backcall-0.1.0             |             py_0          13 KB  conda-forge
    mkl_random-1.0.1           |   py37h77b88f5_1         267 KB
    decorator-4.3.0            |             py_0          10 KB  conda-forge
    numpy-1.15.4               |   py37ha559c80_0          36 KB
    mkl-2019.0                 |              118       178.1 MB
    pandas-0.23.4              |py37h830ac7b_1000         8.7 MB  conda-forge
    prompt_toolkit-2.0.7       |             py_0         218 KB  conda-forge
    python-dateutil-2.7.5      |             py_0         218 KB  conda-forge
    colorama-0.4.0             |             py_0          15 KB  conda-forge
    mkl_fft-1.0.6              |   py37hdbbee80_0         120 KB
    jedi-0.13.1                |        py37_1000         228 KB  conda-forge
    intel-openmp-2019.0        |              118         1.7 MB
    parso-0.3.1                |             py_0          59 KB  conda-forge
    traitlets-4.3.2            |        py37_1000         130 KB  conda-forge
    ipython_genutils-0.2.0     |             py_1          21 KB  conda-forge
    numpy-base-1.15.4          |   py37h8128ebf_0         3.9 MB
    blas-1.0                   |              mkl           6 KB
    ------------------------------------------------------------
                                           Total:       203.7 MB

Спасибо @toniatop. Можете ли вы создать пару сред только со значениями по умолчанию, чтобы увидеть, не проблема в том, как он был скомпилирован для conda-forge?

Переделал все форсирование --channel anaconda, результаты те же.

cc @jjhelmus любые мысли по
https://github.com/pandas-dev/pandas/issues/23516#issuecomment -436958298? TLDR заключается в том, что

  • pd.read_csv в 3-4 раза медленнее на python 3.7 по сравнению с python 3.6
  • замедление (по-видимому) только окна
  • наблюдается на пакетах из conda-forge и по умолчанию

Я также протестировал это с предварительно созданными колесами из: https://www.lfd.uci.edu/~gohlke/pythonlibs/ с теми же результатами.

Я также запустил исходную сборку последнего кода GitHub с python setup.py bdist_wheel с python 3.7.1 и получил те же результаты.

Интересно, изменилось ли что-то в сценарии сборки или какой-то флаг компиляции в Windows.

Я также запустил исходную сборку последнего кода GitHub с python setup.py bdist_wheel с python 3.7.1 и получил те же результаты.

Вы также пробовали собирать из исходников с помощью 3.6?

Сегодня я попробую собрать Python 3.6.7. Я также буду использовать последнюю версию cython на случай, если виноват.

Спасибо всем, кто подтвердил это на windows.

Я просто перестроил последнюю версию Pandas (0.23.4+) из исходного кода с последней версией Cython 0.29 на Python 3.6.7 в Windows 10 и скорость синтаксического анализа _fast_. Кажется, это каким-то образом связано с Python 3.7 в Windows. Не уверен, что это могло быть. Передает ли система ввода-вывода Python данные синтаксическому анализатору Cython / C? Была ли скомпилирована версия Python 3.7 без оптимизации?

Microsoft Windows [Version 10.0.16299.726]
(c) 2017 Microsoft Corporation. All rights reserved.

Python 3.6.7 (v3.6.7:6ec5cf24b7, Oct 20 2018, 13:35:33) [MSC v.1900 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 7.1.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import pandas as pd

In [2]: pd.show_versions()

INSTALLED VERSIONS
------------------
commit: None
python: 3.6.7.final.0
python-bits: 64
OS: Windows
OS-release: 10
machine: AMD64
processor: Intel64 Family 6 Model 158 Stepping 10, GenuineIntel
byteorder: little
LC_ALL: None
LANG: None
LOCALE: None.None

pandas: 0+unknown
pytest: None
pip: 10.0.1
setuptools: 39.0.1
Cython: 0.29
numpy: 1.15.4
scipy: None
pyarrow: None
xarray: None
IPython: 7.1.1
sphinx: None
patsy: None
dateutil: 2.7.5
pytz: 2018.7
blosc: None
bottleneck: 1.2.1
tables: None
numexpr: 2.6.8
feather: None
matplotlib: None
openpyxl: None
xlrd: None
xlwt: None
xlsxwriter: None
lxml: None
bs4: None
html5lib: None
sqlalchemy: None
pymysql: None
psycopg2: None
jinja2: None
s3fs: None
fastparquet: None
pandas_gbq: None
pandas_datareader: None
gcsfs: None

In [3]: import io

In [4]: import numpy as np

In [5]: %time df = pd.DataFrame(np.random.randn(1000000, 10), columns=('COL{}'.format(i) for i in range(10)))
Wall time: 207 ms

In [6]: %time csv = io.StringIO(df.to_csv(index=False))
Wall time: 13.2 s

In [7]: %time df2 = df2 = pd.read_csv(csv, float_precision='high')
Wall time: 1.96 s

Я разместил ссылку на эту проблему в системе отслеживания проблем Python, чтобы они хотя бы могли посмотреть. Поскольку производительность в Linux кажется хорошей, я надеюсь, что исправление компиляции / конфигурации может решить эту проблему для Windows.

https://bugs.python.org/issue35195

Просто чтобы вычеркнуть из списка вероятного подозреваемого - версия MSVC не имеет значения.

# builds with MSVC 2017 with python 3.7 (assuming installed)
λ python setup.py build_ext -i

# %timeit pd.read_csv('tmp.csv')
# 14.6 s ± 701 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

# builds with MSVC 2015
λ "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64
λ python setup.py build_ext -i -f

# %timeit pd.read_csv('tmp.csv')
# 15.2 s ± 2.27 s per loop (mean ± std. dev. of 7 runs, 1 loop each)

Была ли скомпилирована версия Python 3.7 без оптимизации?

Нет, расширения 3.7 продолжают собираться с помощью /Ox

Замедление происходит только в методах, связанных с вводом-выводом?

Кажется, проблема на самом деле в парсинге с плавающей запятой? Что странно, потому что наш xstrtod (?) Вообще не взаимодействует с Python.

Фактически, как заметил @dragoljub , использование парсера round_trip выполняется быстрее, что ДЕЙСТВИТЕЛЬНО вызывает обратный вызов python

In [1]: %timeit pd.read_csv('tmp.csv')
15.2 s ± 2.27 s per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [2]: %timeit pd.read_csv('tmp.csv', float_precision='precise')
18.9 s ± 984 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [3]: %timeit pd.read_csv('tmp.csv', float_precision='round_trip')
8.67 s ± 205 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Я тестировал чистый синтаксический анализ 0-9 INT, и он также примерно в 3,5 раза медленнее на Python 3.7.1 в Windows. Так что у меня такое чувство, что эта проблема связана с поступающими данными до того, как мы перейдем к какому-либо синтаксическому анализу (с плавающей точкой или другим способом).

Я также вижу подозрительную строку кода, вызываемую в Python 3.7, но не в 3.5.2:

{built-in method _thread.allocate_lock}

Может ли это быть что-то новое в Python 3.7.1, которое прерывает работу синтаксического анализатора? Нужно ли нам по-другому выпускать GIL для Python 3.7?

__DataFrame Настройка: __

import io
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randint(0, 9, (1000000, 10)), columns=('COL{}'.format(i) for i in range(10)))
csv = io.StringIO(df.to_csv(index=False))

`` питон
print (df.head (). to_csv (index = False))

COL0, COL1, COL2, COL3, COL4, COL5, COL6, COL7, COL8, COL9
2,1,7,3,2,3,0,4,5,5
6,3,1,7,0,3,6,3,0,8
6,8,4,2,1,5,1,4,3,3
0,8,5,8,0,4,1,8,4,1
4,8,0,0,4,0,3,0,6,3

__Python 3.7.1 & Pandas 0.23.4 -- Slow__
```python
3676 function calls (3642 primitive calls) in 2.132 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    2.075    2.075    2.075    2.075 {method 'read' of 'pandas._libs.parsers.TextReader' objects}
        1    0.039    0.039    0.039    0.039 internals.py:5017(_stack_arrays)
        1    0.009    0.009    2.132    2.132 parsers.py:414(_read)
        1    0.004    0.004    0.004    0.004 parsers.py:1685(__init__)
        1    0.000    0.000    0.000    0.000 {method 'close' of 'pandas._libs.parsers.TextReader' objects}
      161    0.000    0.000    0.000    0.000 common.py:811(is_integer_dtype)
      206    0.000    0.000    0.000    0.000 common.py:1835(_get_dtype_type)
      824    0.000    0.000    0.000    0.000 {built-in method builtins.isinstance}
        2    0.000    0.000    0.000    0.000 {built-in method nt.stat}
      8/2    0.000    0.000    0.001    0.000 <frozen importlib._bootstrap>:978(_find_and_load)
      4/3    0.000    0.000    0.000    0.000 base.py:255(__new__)
       76    0.000    0.000    0.000    0.000 base.py:61(is_dtype)
        2    0.000    0.000    0.001    0.000 {pandas._libs.lib.clean_index_list}
        1    0.000    0.000    2.132    2.132 {built-in method builtins.exec}
      462    0.000    0.000    0.000    0.000 {built-in method builtins.issubclass}
       41    0.000    0.000    0.000    0.000 {built-in method numpy.core.multiarray.array}
    89/78    0.000    0.000    0.000    0.000 {built-in method builtins.len}
       86    0.000    0.000    0.000    0.000 {built-in method builtins.hasattr}
      149    0.000    0.000    0.000    0.000 generic.py:7(_check)
        1    0.000    0.000    0.040    0.040 internals.py:4880(form_blocks)
      3/2    0.000    0.000    0.001    0.001 series.py:166(__init__)
       13    0.000    0.000    0.000    0.000 internals.py:3148(get_block_type)
      245    0.000    0.000    0.000    0.000 {built-in method builtins.getattr}
        7    0.000    0.000    0.000    0.000 {built-in method numpy.core.multiarray.empty}
       12    0.000    0.000    0.000    0.000 cast.py:971(maybe_cast_to_datetime)
        3    0.000    0.000    0.000    0.000 internals.py:237(mgr_locs)
        1    0.000    0.000    0.000    0.000 internals.py:3363(_rebuild_blknos_and_blklocs)
        8    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:157(_get_module_lock)
        2    0.000    0.000    0.000    0.000 {built-in method pandas._libs.lib.array_equivalent_object}
        2    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:882(_find_spec)
       12    0.000    0.000    0.000    0.000 series.py:4019(_sanitize_array)
        2    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:1356(find_spec)
       16    0.000    0.000    0.000    0.000 {built-in method _thread.allocate_lock}
        1    0.000    0.000    2.075    2.075 parsers.py:1846(read)
        2    0.000    0.000    0.000    0.000 missing.py:189(_isna_ndarraylike)
        2    0.000    0.000    0.000    0.000 {method 'reduce' of 'numpy.ufunc' objects}
        1    0.000    0.000    2.117    2.117 parsers.py:1029(read)
        1    0.000    0.000    2.132    2.132 parsers.py:542(parser_f)

__Python 3.5.2 и Pandas 0.23.4 - быстро__

%prun df2 = pd.read_csv(csv, float_precision=None)

2623 function calls (2616 primitive calls) in 0.661 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.604    0.604    0.605    0.605 {method 'read' of 'pandas._libs.parsers.TextReader' objects}
        1    0.039    0.039    0.039    0.039 internals.py:4801(_stack_arrays)
        1    0.011    0.011    0.661    0.661 parsers.py:423(_read)
        1    0.004    0.004    0.004    0.004 parsers.py:1677(__init__)
        1    0.000    0.000    0.000    0.000 {method 'close' of 'pandas._libs.parsers.TextReader' objects}
      3/2    0.000    0.000    0.001    0.000 base.py:181(__new__)
      160    0.000    0.000    0.000    0.000 common.py:777(is_integer_dtype)
      186    0.000    0.000    0.000    0.000 common.py:1773(_get_dtype_type)
      622    0.000    0.000    0.000    0.000 {built-in method builtins.isinstance}
      108    0.000    0.000    0.000    0.000 {built-in method builtins.hasattr}
        1    0.000    0.000    0.605    0.605 parsers.py:1837(read)
        1    0.000    0.000    0.000    0.000 {pandas._libs.lib.clean_index_list}
      129    0.000    0.000    0.000    0.000 {built-in method builtins.getattr}
      118    0.000    0.000    0.000    0.000 generic.py:7(_check)
        1    0.000    0.000    0.039    0.039 internals.py:4645(form_blocks)
       10    0.000    0.000    0.000    0.000 cast.py:935(maybe_cast_to_datetime)
       61    0.000    0.000    0.000    0.000 dtypes.py:85(is_dtype)
      415    0.000    0.000    0.000    0.000 {built-in method builtins.issubclass}
        1    0.000    0.000    0.661    0.661 {built-in method builtins.exec}
        1    0.000    0.000    0.661    0.661 parsers.py:557(parser_f)

Я также обнаружил это исправление ошибки некоторое время назад, которое внесло некоторые изменения в pandas/src/parser/io.c PyGILState_Ensure () был вызван, возможно, по-разному взаимодействуя в системе Windows с потоками на Python 3.7.

11790

https://github.com/pandas-dev/pandas/pull/11790/files#diff -006bfcefd42c2be38e538fdd3219dbfdL125

Я был бы удивлен, что изменение имеет значение, но я здесь в растерянности, так что, может быть! Другая возможность заключается в том, что cython внес некоторые изменения в логику потоковой передачи для совместимости с python 3.7 - опять же, не думаю, что проблема здесь, но возможно какое-то плохое взаимодействие.
https://github.com/cython/cython/issues/1978

Я был бы удивлен, что изменение имеет значение, но я здесь в растерянности, так что, может быть! Другая возможность заключается в том, что cython внес некоторые изменения в логику потоковой передачи для совместимости с python 3.7 - опять же, не думаю, что проблема здесь, но возможно какое-то плохое взаимодействие.
cython / cython # 1978

Хорошая информация. Я просто удивлен, что люди этого не видят в Linux. Далее попробую OSX.

К вашему сведению, мои тайминги выше были на OSX (без замедления)

В пятницу, 9 ноября 2018 г., в 14:16 Gagi [email protected] написал:

Я был бы удивлен, что изменение имеет значение, но я здесь в растерянности, так что, может быть!
Другая возможность заключается в том, что cython внес некоторые изменения в логику потоковой передачи для
python 3.7 compat - опять же, не думаю, что проблема здесь, но
возможно какое-то плохое взаимодействие.
cython / cython # 1978 https://github.com/cython/cython/issues/1978

Хорошая информация. Я просто удивлен, что люди этого не видят в Linux. Больной
попробуйте OSX дальше.

-
Вы получили это, потому что прокомментировали.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/pandas-dev/pandas/issues/23516#issuecomment-437482307 ,
или отключить поток
https://github.com/notifications/unsubscribe-auth/ABQHIl8M-FYdJ366ZxFHd1Rdur0sKyLEks5uteKAgaJpZM4YPD2Y
.

Похоже, что замедление сначала проявляется в Python 3.7.0a4 :

>C:\python-3.7.0a3-amd64\python.exe -m cProfile -s tottime pandascsv.py
         235992 function calls (229477 primitive calls) in 21.525 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
      200   11.316    0.057   11.316    0.057 {method 'astype' of 'numpy.ndarray' objects}
      100    6.596    0.066    6.596    0.066 {pandas._libs.writers.write_csv_rows}
        1    2.111    2.111    2.112    2.112 {method 'read' of 'pandas._libs.parsers.TextReader' objects}       
>C:\python-3.7.0a4-amd64\python.exe -m cProfile -s tottime pandascsv.py
         236639 function calls (230127 primitive calls) in 26.550 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    9.849    9.849    9.850    9.850 {method 'read' of 'pandas._libs.parsers.TextReader' objects}
      200    8.766    0.044    8.766    0.044 {method 'astype' of 'numpy.ndarray' objects}
      100    6.469    0.065    6.469    0.065 {pandas._libs.writers.write_csv_rows}      

Очень интересно. Я попробую Py 3.7.0a3, чтобы подтвердить это в своих системах. Легко ли найти разницу между 0a3 и 0a4 из примечаний к выпуску Pythons?

легко найти в примечаниях к выпуску Pythons?

https://docs.python.org/3.7/whatsnew/changelog.html#python -3-7-0-alpha-4

Может, bpo-29240: Add a new UTF-8 mode: implementation of the PEP 540 ?

См. Также https://github.com/python/cpython/compare/v3.7.0a3...v3.7.0a4

Я также могу подтвердить, что изменения с Python 3.7.0a3 на 3.7.0a4 показывают замедление в моей тестовой системе Win10. Спасибо, что узнали, когда произошло замедление.

__Python 3.7.0a3 - Быстрый синтаксический анализ__

 %prun df2 = pd.read_csv(csv)
         5781 function calls (5743 primitive calls) in 3.062 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    2.953    2.953    2.955    2.955 {method 'read' of 'pandas._libs.parsers.TextReader' objects}
        1    0.063    0.063    0.063    0.063 internals.py:5017(_stack_arrays)
        1    0.016    0.016    3.052    3.052 parsers.py:414(_read)
        1    0.009    0.009    3.062    3.062 <string>:1(<module>)
        1    0.009    0.009    0.009    0.009 parsers.py:1685(__init__)
       32    0.004    0.000    0.004    0.000 {built-in method nt.stat}
        1    0.001    0.001    0.001    0.001 {method 'close' of 'pandas._libs.parsers.TextReader' objects}
      321    0.001    0.000    0.002    0.000 common.py:811(is_integer_dtype)
      516    0.001    0.000    0.001    0.000 common.py:1835(_get_dtype_type)
        7    0.001    0.000    0.001    0.000 {built-in method numpy.core.multiarray.empty}
       32    0.000    0.000    0.005    0.000 <frozen importlib._bootstrap_external>:1235(find_spec)
      988    0.000    0.000    0.000    0.000 {built-in method builtins.isinstance}
      163    0.000    0.000    0.000    0.000 common.py:1527(is_float_dtype)
      718    0.000    0.000    0.000    0.000 {built-in method builtins.issubclass}
      192    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:59(<listcomp>)
      192    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:57(_path_join)
        8    0.000    0.000    0.005    0.001 <frozen importlib._bootstrap_external>:1119(_get_spec)
      133    0.000    0.000    0.000    0.000 {built-in method builtins.getattr}
       68    0.000    0.000    0.000    0.000 generic.py:7(_check)

__Python 3.7.0a4 - Медленный синтаксический анализ__

 %prun df2 = pd.read_csv(csv)
         8007 function calls (7219 primitive calls) in 14.192 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1   14.092   14.092   14.094   14.094 {method 'read' of 'pandas._libs.parsers.TextReader' objects}
        1    0.061    0.061    0.062    0.062 internals.py:5017(_stack_arrays)
        1    0.016    0.016   14.192   14.192 parsers.py:414(_read)
        1    0.008    0.008    0.008    0.008 parsers.py:1685(__init__)
       32    0.004    0.000    0.004    0.000 {built-in method nt.stat}
        1    0.001    0.001    0.001    0.001 {method 'close' of 'pandas._libs.parsers.TextReader' objects}
      321    0.001    0.000    0.002    0.000 common.py:811(is_integer_dtype)
      516    0.001    0.000    0.001    0.000 common.py:1835(_get_dtype_type)
        7    0.001    0.000    0.001    0.000 {built-in method numpy.core.multiarray.empty}
    115/4    0.000    0.000    0.001    0.000 abc.py:194(__subclasscheck__)
       32    0.000    0.000    0.005    0.000 <frozen importlib._bootstrap_external>:1322(find_spec)
 1324/988    0.000    0.000    0.002    0.000 {built-in method builtins.isinstance}
  937/725    0.000    0.000    0.002    0.000 {built-in method builtins.issubclass}
      163    0.000    0.000    0.000    0.000 common.py:1527(is_float_dtype)
      192    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:57(_path_join)
      192    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:59(<listcomp>)
        8    0.000    0.000    0.005    0.001 <frozen importlib._bootstrap_external>:1206(_get_spec)
    89/78    0.000    0.000    0.000    0.000 {built-in method builtins.len}
      192    0.000    0.000    0.000    0.000 {built-in method builtins.getattr}

Я попытался поиграть с настройками режима UTF-8 с переменными ENV и аргументами строки cmd в Windows и не смог получить более высокую скорость синтаксического анализа на Python 3.7.0a4.

https://www.python.org/dev/peps/pep-0540/#proposal

Преимущество подхода принуждения локали заключается в том, что он помогает гарантировать, что обработка кодирования в модулях двоичного расширения и дочерних процессах согласована с обработкой кодирования Python. Положительная сторона подхода режима UTF-8 заключается в том, что он позволяет встроенному приложению изменять поведение интерпретатора без изменения глобальных настроек локали процесса.

Так возможно ли, что где-то в расширении синтаксического анализатора C мы можем просто установить языковой стандарт на UTF-8, и эта проблема исчезнет в Windows? Я надеялся, что настройки переменной ENV решат проблему, но это не повлияло на мое тестирование.

Я сравнил инструкцию df2 = pd.read_csv(csv) на Python 3.7.0a3 и a4 в профилировщике Visual Studio. Виновником является функция isdigit вызываемая в модуле расширения parsers . На 3.7.0a3 функция работает быстро на ~ 8% выборок. На 3.7.0a4 функция работает медленно на ~ 64% выборок, потому что она вызывает функцию _isdigit_l , которая, кажется, обновляет и восстанавливает языковой стандарт в текущем потоке каждый раз ...

3.7.0a3:
Function Name   Inclusive Samples   Exclusive Samples   Inclusive Samples % Exclusive Samples % Module Name
 + [parsers.cp37-win_amd64.pyd] 705 347 28.52%  14.04%  parsers.cp37-win_amd64.pyd
   isdigit  207 207 8.37%   8.37%   ucrtbase.dll
 - _errno   105 39  4.25%   1.58%   ucrtbase.dll
   toupper  24  24  0.97%   0.97%   ucrtbase.dll
   isspace  21  21  0.85%   0.85%   ucrtbase.dll
   [python37.dll]   1   1   0.04%   0.04%   python37.dll
3.7.0a4:
Function Name   Inclusive Samples   Exclusive Samples   Inclusive Samples % Exclusive Samples % Module Name
 + [parsers.cp37-win_amd64.pyd] 8,613   478 83.04%  4.61%   parsers.cp37-win_amd64.pyd
 + isdigit  6,642   208 64.04%  2.01%   ucrtbase.dll
 + _isdigit_l   6,434   245 62.03%  2.36%   ucrtbase.dll
 + _LocaleUpdate::_LocaleUpdate 5,806   947 55.98%  9.13%   ucrtbase.dll
 + __acrt_getptd    2,121   1,031   20.45%  9.94%   ucrtbase.dll
   FlsGetValue  647 647 6.24%   6.24%   KernelBase.dll
 - RtlSetLastWin32Error 296 235 2.85%   2.27%   ntdll.dll
   _guard_dispatch_icall_nop    101 101 0.97%   0.97%   ucrtbase.dll
   GetLastError 46  46  0.44%   0.44%   KernelBase.dll
 + __acrt_update_multibyte_info 1,475   246 14.22%  2.37%   ucrtbase.dll
 - __crt_state_management::get_current_state_index  1,229   513 11.85%  4.95%   ucrtbase.dll
 + __acrt_update_locale_info    1,263   235 12.18%  2.27%   ucrtbase.dll
 - __crt_state_management::get_current_state_index  1,028   429 9.91%   4.14%   ucrtbase.dll
   _ischartype_l    383 383 3.69%   3.69%   ucrtbase.dll

Отличная работа по отладке этого. Я предполагаю, что любые другие пути кода, вызывающие isdigit, также будут замедляться в Windows.

Просто примечание для людей, которые смотрят на xstrtod (и спасибо за это, кстати, это похоже на действительно сложную проблему): их два (# 19361). Я не понимаю, что используется в каком контексте.

Возможно, я нашел пример чистого Python, который, кажется, показывает аналогичное, но меньшее замедление в 2,5 раза. Также обратите внимание, что для кода 3.7.1 вариабельность в 15 раз выше. Возможно, это указывает на то, что аргумент языкового стандарта передается / используется в некоторых вызовах, но не в других.

Может ли кто-нибудь протестировать это на Linux и посмотреть, заметите ли вы разницу?

__Python 3.7.1__

digits = ''.join([str(i) for i in range(10)]*10000000)
%timeit digits.isdigit() # --> 2.5X slower on python 3.7.1
537 ms ± 14.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

__Python 3.5.2__

digits = ''.join([str(i) for i in range(10)]*10000000)
%timeit digits.isdigit() # --> 2.5X slower on python 3.7.1
215 ms ± 986 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

-> На основе комментариев от: https://bugs.python.org/msg329789
похоже, это чистый тест Unicode. Так что это может быть не связано.

@cgohlke представил красивый минимальный пример, показывающий замедление: https://bugs.python.org/msg329790 Спасибо! 👍

Спасибо за расследование @cgohlke - для 0.24, я полагаю, нам нужно просто вставить ASCII isdigit
функция?

(Лицензия MUSL, MIT)
https://github.com/esmil/musl/blob/master/src/ctype/isdigit.c#L5

@ chris-b1 Я думал о том же, поскольку это довольно простая функция, однако изменение локали будет ограничено. Интересно, как функция windows isdigit вызывает версию локали. Я не думаю, что этот источник доступен.

Интересно, как функция windows isdigit вызывает версию локали. Я не думаю, что этот источник доступен.

Исходный код Windows UCRT доступен в последней версии Windows SDK. Обычно он устанавливается под C:\Program Files (x86)\Windows Kits\10\Source .

Функции isdigit и _isdigit_l определены в ucrt\convert\_ctype.cpp :

extern "C" extern __inline int (__cdecl isdigit)(int const c)
{
    return __acrt_locale_changed()
        ? (_isdigit_l)(c, nullptr)
        : fast_check(c, _DIGIT);
}

extern "C" extern __inline int (__cdecl _isdigit_l)(int const c, _locale_t const locale)
{
    _LocaleUpdate locale_update(locale);

    return _isdigit_l(c, locale_update.GetLocaleT());
}

Следующий комментарий взят из функции _wsetlocale :

// If no call has been made to setlocale to change locale from "C" locale
// to some other locale, we keep locale_changed = 0. Other functions that
// depend on locale use this variable to optimize performance for C locale
// which is normally the case in applications.

Так что, если я правильно понимаю. Даже если мы установим локаль в Python на «C», функция isdigit в Windows все равно будет прибегать к вызову версии isdigit локали, замедляя синтаксический анализ, потому что локальная версия «изменилась».

Так обстоит дело с питоном. 3.7.0a3? Установка языкового стандарта на «C» замедляет синтаксический анализ?

@jreback @TomAugspurger Как вы думаете, простая прокладка функции isdigit в коде синтаксического анализатора C была бы исправлением, которое мы могли бы развлечь?

Предполагается, что для числовых столбцов будет использоваться кодировка, совместимая с ASCII, которая, как мне кажется, должна охватывать все / большинство кодировок файлов csv для цифр.

int isdigit(int c)
{
    return (unsigned)c-'0' < 10;
}

Да, если вы хотите отправить PR, пинговать меня, а если нет, я постараюсь добраться до него в ближайшее время

@ chris-b1 Давай! 😄

@ chris-b1 @jreback Спасибо, что сделали это! Действительно ценю это! 👍 😄

Была ли эта страница полезной?
0 / 5 - 0 рейтинги