• 31Jan

    pycamp-logo-newСегодня рано утром вернулся с pycamp, который прошел в Киеве 30ого января в учебном центре i-klass.

    Организаторы сказали, что это их первая попытка организовывать подобные мероприятия, и как по мне — у них для первого раза получилось довольно не плохо, правда розеток было мало, поэтому моя 17ти дюймовая малютка держалась на аккумуляторах.

    Доклады мне понравились не все, но негатив я высказывать свой не буду, поэтому просто небольшой обзорчик того, что понравилось и запомнилось.

    Александр Шигин (гость из солнечного Рамблера) «Почему Python — тормоз и как заставить его меньше тормозить». Были небольшие обзорчики кода, со сравнениями производительности. Сравнение результатов работы алгоритмов, реализованные разными способами — картежи, дикты, классы. Первые быстрее, но мы и так это знали. Хотя местами были довольно интересные результаты. Был упомянут Cython, но только вскользь, хотя мне бы тема была куда интереснее. Так что после в кулуарах мы написали небольшой хелло ворлд на cython, получили сошник и заюзали в самом питоне.

    Кратко выглядит примерно так

    ваш скрипт

    1. print "Hello World"

    скрипт setup.py:

    1. from distutils.core import setup
    2. from distutils.extension import Extension
    3. from Cython.Distutils import build_ext
    4.  
    5. setup(
    6.     cmdclass = {'build_ext': build_ext},
    7.     ext_modules = [Extension("helloworld", ["helloworld.pyx"])]
    8. )

    получаем сошник

    1. $ python setup.py build_ext –inplace

    и дальше его используем в ваших скриптах.

    1. >>> import helloworld
    2. Hello World

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

    Для себя отметил, что им как раз можно пользоваться для оптимизации питонячего кода практически без ограничений в использовании приятного синтаксиса питона. У себя в бложке буду освежать свои успехи в этом деле.

    Юрий Юревич «Рецепты декораторов». Лично для себя ничего нового не увидел, кроме того, что довольно грамотно все разложено по полочкам и что несомненно помогло упорядочить в голове знания.

    Михаил Кашкин (замляк из Днепра) «Работа с хранилищами данных в Google App Engine, отличия от реляционной модели». Я Апсы еще не юзал вообще. Но в скором времени мне таки придется уткнуть свой нос у туда. И пока то, что я узнал — мне не очень понравилось. Реляционных БД там нет вообще. Только их не реляционная БД и мемкеш.

    Мое первое впечатление — это модели бд, как в классической ОРМ, при этом кладутся данные в виде модели и в виде этой же модели забираются, с вытекающими ограничениями. Фишка которая сразу смутила весь зал — если вы копили-копили данные, а потом захотели добавить еще одно поле в модель, то старые данные, построенные на старой модели не обновятся, а нужно руками доставать каждого и задавать ему новое поле, и по словам Михаила — чем больше вы делаете выборку, тем дольше она получается.

    В кулуарах мне рассказали немного больше о самом App Engine. Он не совсем на шару, а в нем есть лимиты, я пологаю, что лимиты на все. Причем при приодалении этих лимитов вам просто закрывают доступ к сайту, хотя по совести их просто надо не давать использовать больше. И хотя питон с джангой были первыми в арсенале App Engine – они там со своими ограничениями. Так что 40 минут доклада оставило для меня много вопросов.

    Александр Соловьев. «Redis: Дикий Запад баз данных». Если коротко — то Redis — этот мемкешед, который сторит данные на винте с промежуточным хранилищем в памяти. С типами данными не только строки но и инты, листы, сеты. И с довольно обширным функционалом для их применения. Мастер-Слейв репликация, кстати только в этом наверно редис проигрывает мемкешу, т.к. мемкеш может использовать несколько серверов и данные между ними отлично распределять ( но редис держит данные на винте а не в памяти ). Ну и конечно же, Александр, как авторитетный велосипедист не мог не написать к редису чего-то своего pyredis ( питонячий клиент для редиса )

    Не мог не оценить подачу материала Александром. Очень живо, я даже подумал что презентация получилась в стиле теле-магазина: «Вы хитите это — пожалуйсто — редис отлично с этим справляется, это – и это вы можете сделать как 2 пальца об асфальт и то и то…». Но я бы на его месте такой продукт подавал как Стив Джобс — Макбук Аир. «Представте систему, которая быстрее мемкеша но данные сторит на винте, с типизацией ячеек и т.д. и т.п. И в конце Редис» Ну что-то в этом стиле.

    В любом случае, Александру спасибо. Будем смотреть, будем пробовать. Интересно, он кешовый бекенд для редиса на джанге уже написал?

    Владимир Пузанов и Владимир Кирилов «Расширения и встраивание Python». Эти два молодых хакера рассказали о том где можно применять питон, с чем и как его можно связывать. Jython, IronPython и многое другое, что я еще не запомнил. Надеюсь где нить раздобыть их презентацию. Но для себя отложил Stackless Python — у него очень «крутые» треды, на сколько крутые — я уже буду пробовать ручками сам. И когда я говорю о Stackless мне уже какой раз предлогают глянуть на greenlet. Общее впечатление о докладе осталось очень хорошее – хороший обзор, живая подача материал и оставило много вопросов (как и должно быть в подобных докладах). В конце парни показали прикольный примерчик как они питоном хачат сафари и меняют в нем титл через его жсный движок. Хотелось бы ответить всем бегающим по залу участникам с вопросам «Нафига надо было хачить софари». Объясняю — просто так!!! Просто точка ( довольно прикольная ) в докладе о расширениях и встраиваниях питона, обидно, что многие из всего доклада запомнили только эту точку.

    Андрей Мишковски «Использование Python в ГИС» . Проблематика Гиографические Информационные Системы для меня была нова, но подача информации была доступна и понятна даже слушателю не знакомым с темой. Так что если кто хочет может просмотреть презентацию, и дождаться выхода видео.

    Сергей Кирилов. «WebSockets в twisted». WebSockets — это новое расширение протокола HTTP в сторону двухстороннего взаимодействия клиент-сервер с одним коннектом, которая описана в стандарте HTML5. Поддерживается пока не всеми ( поэтому пользуемся библиотечкой, которая подменяет стандарт для тех, кто его еще не поддерживает ). Я мог пропустить, но по моему twisted-у был отведен один слайд, на котором выведено 42 строчки кода и сказано, что их 42 :) Кстати нагугли и хабровскую статью на эту тему.

    Не могу не оценить рисковый ход Сергея — реальная демонстрация продукта. Заработало почти с первого раза. У меня так никогда не получалось. Простенький чатик с инпутом и кнопочкой сабмит — впечатлил всех но не демострацией работы а то что почти все, у кого был ноут и получалось воспользоваться вайфаем — начали болтать и прикалываться друг с другом на большом экране, да так что в зале поднялся шум и гам, было очень весело, но по-моему не все успели задать вопросы.

    Сергей, если у вас сохранилась копия этой болтавни в чате — выложите куда-то, было прикольно :)

    И последний из понравившихся мне докладов был у Ивана Моргуна, сразу после нее я и убежал, т.к. надо было успеть на поезд обратно. Доклад был о «Работа с платежными системами в Django (PayPal, WebMoney)». Из джанго я ничего интересно для себя не вынес, но некоторые интересные моменты для PayPal подчеркнул.

    Организаторам, спонсорам и докладчикам мероприятия огромное спасибо. У вас все отлично получилось. Давайте как нить повторим. :)

    Еще о pycamp:
    curvedbrain.org “Мысли по мотивам PyCamp Kyiv”
    Макс Ищенко “мысли к вчерашнему pycamp”
    Vladimir PyCamp впечатления
    Дмитрий Гайворонский “PyCamp @ Kiev, 30 Jan 2010″
    … пишите в комментах ссылки на свои посты о кемпе …

    Rating 3.00 out of 5
    [?]

    Tags: , ,

  • 11Dec

    ai_bolit

    Всем привет. Да, знаю, я давно не писал. Ну простите, и как это не банально, был занят. А заставила меня написать одна мысля. И пожалуйста, дочитайте это до конца, потому что или это очень круто или я опять что то не понимаю, и с температурой 38 мне лучше за клаву не садиться.

    Кеш. Я им пользуюсь для того, чтобы данные, которые я долго вычисляю — положить в память куда нить, чтоб если они понадобились — быстро их оттуда взять. Ну а если их там нет, то просто пересчитать и положить. Если вы им пользуетесь также, то читайте дальше иначе напишите комментарий, который начнется со слов: «Тю, блин, а я его совершенно по другому юзаю, глянь…»

    Т.е. на сетах и гетах все сводится к примерно следующему алгоритму.

    1. from django.core.cache import cache
    2.  
    3. def setter(key,l_value,timeout=0):
    4.     val = cache.get(key)
    5.     if val is None:
    6.         val = l_value()
    7.         cache.set(key,val,timeout)
    8.     return val

    где l_value — это ссылка на функцию, значение которой будет получено, в случае если его нет в кеше.

    Вот этот умопомрачительный алгоритм у меня лежит в основе кеширования.

    Хух… если у вас также, то идете дальше. Надеюсь сейчас осталось достаточно народу.

    Прогуливаясь легкой и непринужденной походкой по блогосфере рунете я уже в который раз натыкаюсь на довольно странное решение следующей проблемы.

    Если есть какие либо данные которые системе нужны часто, но вычисляются долго, то их прямое получение по алгоритму, описанному выше — просто убивает систему. Потому что как только они пропадают из кеша — все, кому нужны эти данные — начинают скопом — все вместе их получать. Например статистика по пользователям у вас вычисляется 5 сек, а выводится на главной странице, с посещаемостью 50 чел в сек, значит одновременно эти данные будут получать 250 процессов – что, может привести к смерти.

    Решение рунета — 2 кеша. В один кладем с одним эксперейшеном, в другой с таким же, но чуть больше. Я думаю многие натыкались на такие решения, но вкратце — если заэкспаирилось в первом — берем из второго, но первый, кто узнал, о том, что заэкспаирилось — пересчитывает.

    Тут просто тьма тьмущая узких мест

    1.Старт у системы должен быть особый. Т.е. в нулевой точке в кеше уже должны быть часто доступные данные.
    2.У вас двойные данные в кеше, т.е. две копии, а ведь часто бывает и такое, что трудновычисляемые данные — это и большие данные.
    3.И последнее — если процесс, который вычисляет заекспаревшиеся данные — умирает. То умирают все. Явно теряем в отказоустойчивости.

    Кратко опишу свой алгоритм решения, и построенный на нем джанговый кешовый бекенд (за базовый взят мемкешовый).

    Если в ячейку с ключем класть не данные, а хеш из двух значений — данные, и время, когда их надо обновить. (ТАДАМ избавились от второго пункта)

    А что если ты перед началом вычислений будеш класть в другой системый и уникальный ключ в кеше время, когда первый, начавший вычисления – планирует их закончить. А остольные процессы, которые захотят получить данные и не увидят их — смогут орентироваться на системный ключь, чтоб понимать, что данные скоро будут и их необходимо подождать или мы не дождались и попробуем еще раз. (ТАДАМ избавились от первого и третьего)

    А теперь скучный код. Чтоб легче было читать — его необходимо скрестить с алгоритмом, который я описывал выше. И если функция гет — вернет None то эти данные сразу начнут вычисляться.

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

    1. from django.core.cache.backends.memcached import CacheClass as BaseCacheClass
    2. from datetime import datetime,timedelta
    3. from time import sleep
    4. from random import random
    5.  
    6. ADDITION_EXP_TIME = 20
    7. TIME_FOR_CREATE = 5
    8.  
    9. class CacheClass(BaseCacheClass):
    10.     def add(self, key, value, timeout=0):
    11.         timeout = timeout or self.default_timeout
    12.         value = {'v':value,'e':datetime.now()+timedelta(seconds=timeout)}
    13.         super(CacheClass,self).add(key,value,timeout+ADDITION_EXP_TIME)
    14.        
    15.     def set(self, key, value, timeout=0):
    16.         timeout = timeout or self.default_timeout
    17.         value = {'v':value,'e':datetime.now()+timedelta(seconds=timeout)}
    18.         super(CacheClass,self).set(key,value,timeout+ADDITION_EXP_TIME)
    19.    
    20.     def get(self,key, default=None):
    21.         wait_next_val = 0
    22.         while True:
    23.             wait_next_val += 0.1
    24.             value = super(CacheClass,self).get(key,default)
    25.             now = datetime.now()
    26.            
    27.             if value is not None and now<value['e']:
    28.                 return value['v']
    29.            
    30.             wait_system_key = 'wait_system__%s__wait_system'%key
    31.             wait_system = super(CacheClass,self).get(wait_system_key)
    32.            
    33.             # if you find expired key first or you don't wait the next person
    34.             if wait_system is None or wait_system<now:
    35.                 super(CacheClass,self).set(wait_system_key,datetime.now()+timedelta(seconds=TIME_FOR_CREATE),TIME_FOR_CREATE + 5)
    36.                 return None
    37.            
    38.             #if somebody already getting a new value
    39.             if value is not None:
    40.                 return value['v']
    41.            
    42.             sleep(random()*wait_next_val)

    И на всякий случай. Если вы все таки считаете это отличной идее. Кладем это в файлик с незамысловатым названием smart_cache.py рядом с settings.py, а в settings.py записываем

    1. CACHE_BACKEND = "smart_cache://127.0.0.1:11211"

    Rating 3.00 out of 5
    [?]

    Tags: , , ,

  • 01Oct

    Я уже посягал на суверинитет джанги. Но это было давно и не правда. Более того, меня тогда убедили, что делаю я глупости, и я даже убедился сам, в последствии, что на самом деле делаю глупости. Но мысть о том, что urls.py не нужен – не перестает меня беспакоить. Поэтому очередно фин, аморальный бред – называйте как хотите, но мне безумно нравится.

    Идея проста. Вьюха и урла всегда вместе – а значит одно должно быть декоратаром для другого.

    Итак главный urls.py имеет обычный вид

    1. from django.conf.urls.defaults import *
    2.  
    3. urlpatterns = patterns('',
    4.     (r'^someurl/',include('someapp.url_view')),
    5. )

    /someapp/url_view.py – тут у нас сбстно и хранятся вьюхи с урлами. Как видите, декоратор tourl нам земенил запись в urls.py

    1. from django.http import HttpResponse
    2. from tourl import tourl
    3.  
    4. @tourl(r'^and/$')
    5. def and_(request):
    6.     return HttpResponse('and')
    7.  
    8. @tourl(r'^gg/$')
    9. def index(request):
    10.     return HttpResponse('OK')

    /someapp/tourl.py – ну и код самого декоратора

    1. from django.conf.urls.defaults import *
    2. import sys
    3. import functools
    4. def tourl(url_patern,*args,**kwargs):
    5.     def paramed_decorator(func):
    6.         @functools.wraps(func)
    7.         def decorated(self):
    8.             return func(self)
    9.         module =sys.modules[func.__module__]
    10.        
    11.         if not hasattr(module, 'urlpatterns'):
    12.             module.urlpatterns = patterns('',)
    13.              
    14.         module.urlpatterns   += patterns('',
    15.             url(url_patern,decorated,*args,**kwargs),
    16.         )
    17.         return decorated
    18.     return paramed_decorator

    Помоему и симпотично и по производительности не бьет. Вобщем конфетка! Что скажите?

    PS: Добавил снипет.

    PSS: В снипетсах посоветовали добавить functools.wraps

    PSS: А еще можно использовать и так

    1. from django.http import HttpResponse
    2. from tourl import tourl, patterns,url
    3.  
    4.  
    5.  
    6. @tourl(r'^and/$')
    7. def and_(request):
    8.     return HttpResponse('and')
    9.  
    10.  
    11. def index(request):
    12.     return HttpResponse('OK')
    13.  
    14. tourl(r'^gg/$')(index)
    15.  
    16.  
    17. def ordinary(request):
    18.     return HttpResponse('Ordinary')
    19.  
    20. urlpatterns += patterns('',
    21.             url(r'^ord/$',ordinary)
    22.         )

    Rating 3.00 out of 5
    [?]

    Tags: , , , , ,

  • 13Sep

    Развел небольшой холивар на своем любимом блоге.

    Rating 3.00 out of 5
    [?]

    Tags: , , ,

  • 01Aug

    с утра зашел проверить утренние филы. И вот наткнулся celery. Теперь тяжеловесные задачи на откладывать на потом. И делается это очень просто, по крайне мене судя по документации. Тут более подроная апишка.

    Оставил себе таск на выходные порытся и тут. Обо всем напишу тут.

    PS: первое, к чему бы я сразу это прикрутил – это отсылка мыла. Ее всегда полезно отложить :)

    Всем удачных выходных.

    Rating 3.00 out of 5
    [?]

    Tags: , , , , , , ,

  • 29Jul

    только что наткнулся на этот “АП”, хотя на самом деле – это такой сборничек маленьких полезных функций и пары декораторов. В принфипе ничего сверхестественного. Но смотреть всем обязательно.

    Rating 3.00 out of 5
    [?]

    Tags: , ,

  • 24Jun

    Пока мой ноут еще жив, а читатели делают ставки, я решил перед сном еще расковырять django-debug-tolbar.

    По сути все панели построены на хаках. Т.е. В архитектуре самого движка не закладывалась такая фишка. Т.е. К примеру берут класс BaseCache для из модуля django.core.cache.backends.base делают на его основе наследника, который делает тоже самое, только еще и считает. И заменяют полученный класс в модуле. Т.е. теперь там лежит «тулбарный» класс, и джанго для своей кухни будет брать его, а он уже будет делать свои «темные делишки».

    Я для своего csvlog выкавырял оттуда только sql. Теперь я могу еще и вести лог всех запросов, проходящих в вашем апе, и говорить, сколько времени они съели. Сделал сразу компонентную структуру, почти как у этого самого тулбара, так что если что можете отключать.

    А хак этот выглядит совсем не сложно:

    1. from django.db.backends import util
    2. import time
    3. from csvlog.middleware import glog
    4. class DatabaseStatTracker(util.CursorDebugWrapper):
    5.     def execute(self, sql, params=()):
    6.         start = time.time()
    7.         try:
    8.             return self.cursor.execute(sql, params)
    9.         finally:
    10.             stop = time.time()
    11.             glog.dbg(['__SQL__',stop-start,sql,unicode(params)])
    12. util.CursorDebugWrapper = DatabaseStatTracker

    Да, и я не тестил, но очень сильно подозреваю, что теперь кто-то из них двоих не сможет считать сюелины, и скорее всего тот, чей ап идет позже в INSTALLED_APPS.

    PS: Забыл предварительно проверить свободное место на винте. Бедняга должен умереть свободным.

    Rating 3.00 out of 5
    [?]

    Tags: , , , ,

  • 22Jun

    Исправил много мелких багов, но надо уже написать нормальную доку. Есть еще идея, взять кусочки из джанго тулбара и к примеру дать возможность выводить все СЮЛ запросы.

    Кроме того, сейчас пишу еще одно приложения – простое для принятия платежей. Хотя, получилась довольно универсальная фишка. Так вот в нем я использую эти логи, но есть вероятность, хотя и маленькая, но есть, что комуто логи эти будут не подуше, поетому я еще и заглушку сделал. Такие заглушки можно писать для взаимодейстивя между джанго приложений.

    В папку с аппом добовляем файлик extapp.py

    1. __all__ = ['glog']
    2. from django.conf import settings
    3. if 'csvlog' in  settings.INSTALLED_APPS:
    4.     from csvlog import glog
    5. else:
    6.     class glog():
    7.         @staticmethod
    8.         def get_log_func(self,*args):
    9.             return lambda *args:None
    10.     for n in ['err','imp','inf','log','trc','dbg']:
    11.         setattr(glog,n,staticmethod(lambda *args:None))

    проверяет есть ли апп, если нет, то пишем для него заглушку. А везде в коде просто юзаем

    1. from extapp import glog

    I love Python!

    Rating 3.00 out of 5
    [?]

    Tags: , , ,

  • 17Jun

    Когда делая выборку из объекта родителя и хочется получать объекты наследники, то я использую такой финт

    1. from django.db import models
    2.  
    3. class MBase(models.Model):
    4.     field1 = models.CharField(max_length=10)
    5.     field2 = models.CharField(max_length=10)
    6.     classname = models.CharField(max_length=10)
    7.     def save(self,*args,**kwargs):
    8.         self.classname = self.__class__.__name__.lower()
    9.         super(MBase,self).save(*args,**kwargs)
    10.     @property
    11.     def rel_obj(self):
    12.         return getattr(self, self.classname)
    13.    
    14. class MFirst(MBase):
    15.     myf1 = models.CharField(max_length=10)
    16.    
    17. class MSecond(MBase):
    18.     myf2 = models.CharField(max_length=10)

    А в коде выходит примерно следующее

    1. In [11]: M.MBase.objects.get(id=3)
    2. Out[11]: <MBase: MBase object>
    3.  
    4. In [12]: M.MBase.objects.get(id=3).rel_obj
    5. Out[12]: <MFirst: MFirst object>
    6.  
    7. In [13]: M.MBase.objects.get(id=3).rel_obj.myf1
    8. Out[13]: u'Hi1'

    PS: Чтоб не мучаться, можно вынести функционал в абстрактную модель.

    1. class RelatedBase(models.Model):
    2.     childclassname = models.CharField(max_length=20,editable=False)
    3.     def save(self,*args,**kwargs):
    4.         if not self.childclassname:
    5.             self.childclassname = self.__class__.__name__.lower()
    6.         super(RelatedBase,self).save(*args,**kwargs)
    7.     @property
    8.     def rel_obj(self):
    9.         return getattr(self, self.childclassname)
    10.     class Meta:
    11.         abstract=True

    а все базовые классы уже будут от нее наследоваться

    Rating 3.00 out of 5
    [?]

    Tags: , ,

  • 07Jun

    django
    Хоть выкраить лишнюю минутку было более чем сложно. Последние две недели у меня Django-NonStop.

    Все основаное на идее, которую я описывал ранее.

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

    В репозитарии лежит пример использования этого приложения вместе с апом. Так что можете просто открыть settings.py и глянуть, какие поля в настройках необходимо добавить. Не стандартные поля помечены ##ADD

    Что под капотом?

    Возможность логить. (В шоке?)

    1. from django.http import HttpResponse
    2. from csvlog import glog
    3. def somelog(request):
    4.     glog('executin log by default name')
    5.     glog.err('ERR, some error hapend')
    6.     glog.imp('IMP, some important information')
    7.     glog.inf('INF, some information')
    8.     glog.log('LOG, some log')
    9.     glog.trc('TRC, some trace')
    10.     glog.dbg('DBG, debug information')
    11.     return HttpResponse('OK')

    И вы можете сами указывать какие данные из стека вы хотели бы сторить. Настройка представляет собой набор ссылок на функции.
    Автоматом сторятся данные реквеста и респонса. Точна также вы можете задавать какие куски этих объектов идут к вам в лог.

    Также под ваш лог, автомат создаётся объект в моделях csvlog.models.LogDump. И вы можете импортировать в него данные из логов и работать с ними через вашу ORM. Пожалуй это основной плюс.

    1. python manage.py log_to_base log.csv

    Ну и маленькая рюшечка в нагрузку. Баг репортинг.

    Все несловленные вами эксепшены, ловятся ей, и сторятся в базу. Я когда узнал, сколько всего можно то от ексепшена то узнать, я не был уверен, что мне базы то хватит. А пользователю выводится предложение еще и обматерить вас, ну т.е. оставить свой баг репорт.

    Проект очень, очень нуждается в жесткой критике.

    Rating 3.00 out of 5
    [?]

    Tags: , , , ,

« Previous Entries   

Recent Comments

  • Every body remembers that modern life seems to be not very c...
  • Alexander, спасибо, интересная трактовка. Но целью статьи бы...
  • "И всегда выходит так, что супер силы, супер сразу — это суп...
  • Так, на вскидку - Лукъяненко пишет в жанре фантастика....
  • Не выдержала моя душа, вот по поводу идиотизма которого тебе...