13 юни 2011

Mandelbrot + Web Workers

Категория: Dev,Firefox,HTML5,WebLucho @ 22:28

Обичам фрактална графика и поради липса на по-смислено занимание тези дни, реших да напиша визуализатор за Mandelbrot. Имплементацията ползва готините Web Workers, за да се справи с тоновете сметки и Canvas за да изобрази резултатът на екрана.

48 web worker-a се борят да запълнят 800х600 пиксела пространство и да си призная се справят по-добре от очакваното… е, все още си е бавно, но е 48 пъти по-добре отколкото без възможност за паралелно изпълнение на алгоритъма :D .

Резултатът може да видите тук – http://dailyffs.com/mandelbrot/

А кодът е достъпен тук – https://gist.github.com/1023445

Забележка: работи само с Firefox, защото другите браузъри или нямат web workers или не поддържат предаването на по-сложни обекти от/към worker-ите.


Тагове: , , ,


10 юни 2011

Малко python benchmarking

Категория: DevLucho @ 10:45

Наскоро се сблъсках със следния казус:

Как най-ефективно да преобразувам списък от repr на двойки елементи в списък от двойки елементи (т.е. да eval-на всеки string в python-ски tuple). Пример:


["('text1', 'text2')", "('text3', 'text4')", ... "('textn', 'textm')"]

Ето и четирите начина, които тествах:


from time import time
import re

def time_it(n, func, data):
 start = time()
 out = map(func, data)
 print 'time for case %d:' % n, time()-start
 return out

data = map(repr, zip(map(str, range(10**6)), map(str, range(10**6))))
out = []

# 1 - eval на всеки елемент
out.append(time_it(1, eval, data))

# 2 - премахване на ненужните символи
out.append(time_it(2, lambda x: x[2:-2].split('\', \''), data))

# 3 - match-ване на стойностите с регулярен израз за всеки елемент
pattern = re.compile(r'''\('(\w+)', '(\w+)'\)''')
out.append(time_it(3, lambda x: pattern.search(x).group(1, 2), data))

# 4 - match-ване на стойностите с регулярен израз върху всички елементи обединени в един string
pattern = re.compile(r"'(\w+)'")
start = time()
res = pattern.findall(''.join(data))
out.append(zip(res[::2], res[1::2]))
print 'time for case 4:', time()-start

print 'are they all the same?', len(filter(lambda o: o != out[0], map(lambda x: map(tuple, x), out))) == 0

Ето и времената:


time for case 1: 15.3229999542
time for case 2: 2.14499998093
time for case 3: 1.76999998093
time for case 4: 1.20600008965
are they all the same? True

Познах им класацията по бързодействие още преди да ги напиша :) .

Естествено, най-правилният начин е този, който първи идва в главата на човек – eval. За съжаление обаче, ще трябва доста да почакате! Дори и да се направите на хитри и да пробвате със следния код (който е още по-грозен от вариант номер 4)


eval(repr(data).replace('"', ''))

пак времето нужно за изпълнение е около 10 пъти повече от вариант номер 4.

Макар че четвъртият пример е най-ефективен, не го препоръчвам поради ред причини, но най-вече защото кодът не се ръководи по форматa на данните, а просто агрегира всичко, което е между кавички. За това пък третият вариант е доста близък по време до четвъртия и за разлика от него се ръководи по структурата на данните, не прави един огромен текстов низ и е доста по-кратък и разбираем. Вариант номер 2 го забравете, че съществува ;-)

Та, в заключение – гледайте да използвате по-рядко eval и да балансирате добре между разбираемост и бързодействие.

P.S. Eval is Evil by default… so never use it for evaluating external code or else your program will execute someone else’s code :)


Тагове: , ,


05 юни 2011

Как работи един голям не-ентърпрайз софтуерен проект

Категория: DevLucho @ 16:31

Преди 2 седмици попаднах на това видео от PyCon 2011, в което създателите на едно от най-големите Django приложения – Disqus, разказват как работи то. Disqus е embeddable платформа за коментиране, която има над 500 милиона уникални посетители месечно. Само поради този факт си струва да изгледате видеото… освен това ползват и разработват доста хитри туулове, с които е добре да се запознае човек.

Другото интересно нещо, което намерих е fork на haystack със spatial support – https://github.com/dannercustommade/django-haystack

Точно си мислих да започна да пиша разширение за haystack, което да поддържа новите spatial функции в solr и се оказа, че съм закъснял с 2 месеца. Карай.

Оказа се, че плъгинът не е напълно завършен и spatial функциите не работят с последната версия на solr, така че ще го форкна и ще пробвам да го пооправя.

п.п. haystack е django плъгин за работа със solr и други full-text search engines.



Тагове: , ,


27 май 2011

Тернарен-if в Python

Категория: DevLucho @ 01:02

Както сигурно знаете, в Python писането на тернарен условен преход ternary-if е доста дълъг процес


<cmd A> if <condition> else <cmd B>

докато във всички останали езици обикновено е


<condition> ? <cmd A> : <cmd B>

Това несъмнено е по-грозен и труден за четене начин, но всички са му свикнали – условие, първа команда, втора команда.

Наскоро видях един друг похват използван в два различни плъгина за Django (единият беше south, другият не помня).


<condition> and <cmd A> or <cmd B>

В първите 2 минути като видях този начин на изписване бях доста учуден. Вероятно всеки би бил и вероятно този запис е в пъти по-нечетим от стандартния тернарен-if, но въпреки всичко се доближава повече до обикновения тернарен оператор и сигурно е по-лесен за възприемане от хора с опит в други езици.


Тагове: ,


17 май 2011

jslinux

Категория: Dev,WebLucho @ 16:56

How cool is that…

Не съм сигурен как точно работи това, но очевидно javascript енджините вече са ненормално бързи, за да е възможно емиулирането на операционна система в браузър. Ако още не вярвате на очите си, най-добре го разгледайте сами – http://bellard.org/jslinux/

Let the time of browser-based VMs begin!


Тагове: , ,


14 май 2011

Learn to love Javascript

Категория: Dev,WebLucho @ 13:43

Дойде това време от годината, когато човек може да се наслади на изобилие от качествени презентации, благодарение на Google IO. Първото видео, което изгледах беше от Alex Russell, който говори за бъдещия стандарт на Javascript – Harmony. Harmony ще направи опит да очовечи езика, чрез оператори и похвати, които са дефакто-стандарт на повечето функционалните скриптови езици. Все пак не става дума за кардинална промяна, а за „захаросване“ на синтаксиса, така че кодът написан за предни версии на езика да си е напълно валиден.

Както и да е, това не е най-интересното от презентацията. Най-интересното от нея е едно изречение, което характеризира перфектно Javascript и очертава основното различие между този език и останалите скриптови езици:

You don’t create classes that are state with behaivour attached,
you create behaivour that holds the state that it needs.

Enjoy :)


Тагове: ,


11 май 2011

Django за ненормални хора

Категория: Dev,WebLucho @ 23:07

Говорим за Python 2.5+ и Django 1.2+

Какво ще направите ако ви трябва динамично създаден модел?

Първосигналното решение е да създадете класа на модела и под него да добавяте полетата. Това е погрешно поради ред причини, но най-основната е, че базовия клас на моделите (models.Model) се създава посредством метаклас (models.base.ModelBase), който е отговорен за магиите под капака и веднъж щом е създаден класа няма как да добавяте нови атрибути и магиите да сработят с тях.

Второсигналното решение е да създадете наследник на метакласа, който да е отговорен за динамичното създаване на желания модел. Това е доста по-елегантно и в стила на Python, а и ще можете да използвате метакласове най-накрая и да се похвалите на приятелите си :D .


class MetaDynamicData(models.base.ModelBase):

 def __new__(cls, name, bases, attrs):

   newattrs = {'__module__': 'myapp.models'}

   # Да речем, че искате да добавите динамично по един атрибут за всеки месец
   months = [datetime.datetime(2000, x, 1).strftime('%b').lower() for x in range(1, 13)]
   for m in months:
     newattrs[m] = models.IntegerField()

   return super(MetaDynamicData, cls).__new__(cls, name, (models.Model,), newattrs)

class DynamicData(models.Model):
 """
 Dynamic data is cool!
 """
 __metaclass__ = MetaDynamicData

Ако не сте чували за метакласове, най-добре си прочетете документацията, за да разберете какво се случва.

Дотук добре, но какво става ако използвате Sphinx, за да си генерирате автоматично документация за кода?!
Рано или късно ще забележите, че документацията за DynamicData липсва. Липсва, защото Python държи описанието на всеки обект (за по-просто docstring) в магическия атрибут __doc__, а класът DynamicData се генерира динамично от метаклас. За това е нужно да създадем docstring-a в __new__ на метакласа.


class MetaDynamicData(models.base.ModelBase):

 def __new__(cls, name, bases, attrs):

   newattrs = {'__module__': 'myapp.models'}

   newattrs['__doc__'] = "Dynamic data is cool!"

   # Да речем, че искате да добавите динамично по един атрибут за всеки месец
   months = [datetime.datetime(2000, x, 1).strftime('%b').lower() for x in range(1, 13)]
   for m in months:
     newattrs[m] = models.IntegerField()

   return super(MetaDynamicData, cls).__new__(cls, name, (models.Model,), newattrs)

class DynamicData(models.Model):

 __metaclass__ = MetaDynamicData

Сега вече всичко ще е наред и ще може да се похвалите на приятелите си, че знаете какво е __doc__, което ви отрежда място в челната петица на най-образованите Python програмисти и завинаги ви прави по-skilled, от който и да е PHP програмист (самият факт, че пишете на Python стига, май).

За съжаление Джанго не е кръстен на този филм, но пък е горе-долу толкова силен…


Тагове: , ,


« Предишна страницаСледваща страница »