Как лучше всего оптимизировать вычисления, повторяемые по сетке NxM в Python

Совместное использование запросов - CORS (запрос AJAX кросс-домена AKA) - проблема, с которой может столкнуться большинство веб-разработчиков, в соответствии с политикой Same-Origin-Policy, браузеры ограничивают клиентский JavaScript в изолированной программной среде безопасности, обычно JS не может напрямую взаимодействовать с удаленным сервером из другого домена. В прошлом разработчики создали много сложных способов для достижения запроса ресурсов между доменами, наиболее часто используемыми способами являются:

  1. Использование Flash / Silverlight или серверной стороны в качестве «прокси» для связи с удаленным.
  2. JSON с заполнением ( JSONP ).
  3. Вставляет удаленный сервер в iframe и обменивается данными через фрагмент или window.name, см. здесь .

Эти сложные способы имеют более или менее некоторые проблемы, например, JSONP может привести к дыре в безопасности, если разработчики просто «оценят» его и # 3 выше, хотя он работает, оба домена должны строить строгий контракт между собой, он не гибкий и не элегантный IMHO:)

W3C внедрил совместное использование ресурсов Cross-Origin (CORS) в качестве стандартного решения для обеспечения безопасного, гибкого и рекомендуемого стандартного способа решения этой проблемы.

Механизм

С высокого уровня мы можем просто считать, что CORS - это контракт между клиентом AJAX-вызовом из домена A и страницей, размещенной в домене B, типичным запросом Cross-Origin / ответ будет:

Заголовки заголовков DomainA AJAX

Host DomainB.com
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/json
Accept-Language en-us;
Accept-Encoding gzip, deflate
Keep-Alive 115
Origin http://DomainA.com 

Заголовки ответа домена B

Cache-Control private
Content-Type application/json; charset=utf-8
Access-Control-Allow-Origin DomainA.com
Content-Length 87
Proxy-Connection Keep-Alive
Connection Keep-Alive

Синие части, отмеченные выше, были фактами ядра, Заголовок запроса «Origin» указывает, откуда отправляется запрос на перекрестный запрос или запрос перед полетом », заголовок ответа« Access-Control-Allow-Origin »указывает, что эта страница позволяет удаленный запрос от DomainA (если значение * указывает, что удаленные запросы от любой домен).

Как я уже упоминал выше, W3 рекомендовал браузер для реализации «предпродажного запроса» перед отправкой HTTP-запроса на основе Cross-Origin, в двух словах это запрос HTTP OPTIONS:

OPTIONS DomainB.com/foo.aspx HTTP/1.1

Если foo.aspx поддерживает HTTP-ключ OPTIONS, он может возвращать ответ, как показано ниже:

HTTP/1.1 200 OK
Date: Wed, 01 Mar 2011 15:38:19 GMT
Access-Control-Allow-Origin: http://DomainA.com
Access-Control-Allow-Methods: POST, GET, OPTIONS, HEAD
Access-Control-Allow-Headers: X-Requested-With
Access-Control-Max-Age: 1728000
Connection: Keep-Alive
Content-Type: application/json

Только если ответ содержит «Access-Control-Allow-Origin», И его значение равно «*» или содержит домен, который отправил запрос CORS, выполнив этот запрос условия для условий запроса, передаст фактический запрос кросс-домена и кеширует результат в «Preflight-Result-Cache».

Я писал о CORS три года назад: HTTP-запрос AJAX Cross-Origin

0
задан astro_lukas 30 March 2019 в 22:04
поделиться

1 ответ

Вот метод, который дает ускорение в 10 000 раз на N=310, M=230. Поскольку метод масштабируется лучше, чем исходный код, я ожидаю, что при полном размере задачи коэффициент будет превышать миллион.

В этом методе используется сдвиговая инвариантность задачи. Например, del_x**2 по сути одинаков с точностью до сдвига при каждом вызове do_calc, поэтому мы вычисляем его только один раз.

Если выходные данные из do_calc взвешены до суммирования, проблема перестает быть полностью трансляционно-инвариантной, и этот метод больше не работает. Результат, однако, затем может быть выражен в терминах линейной свертки. На N=310, M=230 это все еще оставляет нам более чем 1000-кратное ускорение. И, опять же, это будет больше при полном размере задачи

Код для исходной задачи

import numpy as np

#N, M = 3108, 2304
N, M = 310, 230

### OP's code

x,y = np.linspace(1,N,num=N),np.linspace(1,M,num=M) # x&y dimensions of image
X,Y = np.meshgrid(x,y,indexing='ij')
all_coords = np.dstack((X,Y)) # moves to 3-D
all_coords = all_coords.astype(int) # sets coords to int

'''
- below is a function that does a calculation on the full grid using the distance between x0,y0 and each point on the grid.
- the function takes x0,y0 and returns the calculated values across the grid
'''
def do_calc(x0,y0):
    del_x, del_y = X-x0, Y-y0
    np.seterr(divide='ignore', invalid='ignore')
    dmx_ij = (del_x/((del_x**2)+(del_y**2))) # x component
    dmy_ij = (del_y/((del_x**2)+(del_y**2))) # y component
    return np.nan_to_num(dmx_ij), np.nan_to_num(dmy_ij)

# now the actual loop

def do_loop():
    dmx,dmy = 0,0
    for pair in all_coords:
        for xi,yi in pair:
            DM = do_calc(xi,yi)
            dmx,dmy = dmx+DM[0],dmy+DM[1]
    return dmx,dmy

from time import time

t = [time()]

### pp's code

x, y = np.ogrid[-N+1:N-1:2j*N - 1j, -M+1:M-1:2j*M - 1J]
den = x*x + y*y
den[N-1, M-1] = 1
xx = x / den
yy = y / den
for zz in xx, yy:
    zz[N:] -= zz[:N-1]
    zz[:, M:] -= zz[:, :M-1]
XX = xx.cumsum(0)[N-1:].cumsum(1)[:, M-1:]
YY = yy.cumsum(0)[N-1:].cumsum(1)[:, M-1:]
t.append(time())

### call OP's code for reference

X_OP, Y_OP = do_loop()
t.append(time())

# make sure results are equal

assert np.allclose(XX, X_OP)
assert np.allclose(YY, Y_OP)
print('pp {}\nOP {}'.format(*np.diff(t)))

Пример выполнения:

pp 0.015251636505126953
OP 149.1642508506775

Код для взвешенной задачи: [1114 ]

import numpy as np

#N, M = 3108, 2304
N, M = 310, 230

values = np.random.random((N, M))
x,y = np.linspace(1,N,num=N),np.linspace(1,M,num=M) # x&y dimensions of image
X,Y = np.meshgrid(x,y,indexing='ij')
all_coords = np.dstack((X,Y)) # moves to 3-D
all_coords = all_coords.astype(int) # sets coords to int

'''
- below is a function that does a calculation on the full grid using the distance between x0,y0 and each point on the grid.
- the function takes x0,y0 and returns the calculated values across the grid
'''
def do_calc(x0,y0, v):
    del_x, del_y = X-x0, Y-y0
    np.seterr(divide='ignore', invalid='ignore')
    dmx_ij = (del_x/((del_x**2)+(del_y**2))) # x component
    dmy_ij = (del_y/((del_x**2)+(del_y**2))) # y component
    return v*np.nan_to_num(dmx_ij), v*np.nan_to_num(dmy_ij)

# now the actual loop

def do_loop():
    dmx,dmy = 0,0
    for pair, vv in zip(all_coords, values):
        for (xi,yi), v in zip(pair, vv):
            DM = do_calc(xi,yi, v)
            dmx,dmy = dmx+DM[0],dmy+DM[1]
    return dmx,dmy

from time import time
from scipy import signal

t = [time()]
x, y = np.ogrid[-N+1:N-1:2j*N - 1j, -M+1:M-1:2j*M - 1J]
den = x*x + y*y
den[N-1, M-1] = 1
xx = x / den
yy = y / den
XX, YY = (signal.fftconvolve(zz, values, 'valid') for zz in (xx, yy))

t.append(time())
X_OP, Y_OP = do_loop()
t.append(time())
assert np.allclose(XX, X_OP)
assert np.allclose(YY, Y_OP)
print('pp {}\nOP {}'.format(*np.diff(t)))

Пример прогона:

pp 0.12683939933776855
OP 158.35225439071655
0
ответ дан Paul Panzer 30 March 2019 в 22:04
поделиться
Другие вопросы по тегам:

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