Архив рубрики: Без рубрики

Падение SKYPE 64 bit в Linux Mint 16 Cinnamon

После установки Mint 16 Cinnamon 2.0 в Скайпе при совершении тестового вызова, ну или просто разговора с кем-либо — последний постоянно падал. Это касается только 64-битной версии. Причиной является отсутствие пакета libasound2-plugins:i386.

Путем раскуривания манов на офсайте Скайпа было найдено следующее решение. Тупо открываем терминал и копипастим туда следующую команду:


sudo aptget install libasound2plugins:i386

Перезагружаем Скайп и радуемся нормальной работе))) Почитать об этом можно тут.

Автор: Роман Дмитриевич

Функциональный стиль в питоне

Пост чисто философский

Периодическое чтение кусков кода, написанных при обострении хаскеля головного мозга, выработало у меня четкую ассоциацию: функциональный стиль — это нечитаемо. Точнее стиль с множеством map/filter/zip. Вот немного облагороженный пример такого кода (автор считает, что с кодом все ок):

Без подсветки синтаксиса

some_res = ", ".join(
map(str,
filter(None,
map(lambda x: getattr(obj.zip, x, None),
['a', 'b', 'c', 'd']))))

some_res = ", ".join(
map(str,
filter(None,
map(lambda x: getattr(obj.zip, x, None),
['a', 'b', 'c', 'd']))))

Без переписывания в многострочный вариант ориентироваться в нем вообще сложно:

Без подсветки синтаксиса

attrs = ['a', 'b', 'c', 'd']
attr_vals = map(lambda x: getattr(obj.zip, x, None), attrs)
non_none_attrs = filter(None, attr_vals)
some_res = ", ".join(map(str, non_none_attrs))

attrs = ['a', 'b', 'c', 'd']
attr_vals = map(lambda x: getattr(obj.zip, x, None), attrs)
non_none_attrs = filter(None, attr_vals)
some_res = ", ".join(map(str, non_none_attrs))

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

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

Без подсветки синтаксиса

x = some_func1(a, b, some_func2(c, d), e)

x = some_func1(a, b, some_func2(c, d), e)

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

Следующий случай — это функциональный стиль в скале. Его чтение у меня не вызывает того чувства трясины, какое вызывал аналогичный код в python/haskell. Тот же пример на 'скалапитоне' выглядел бы так:

Без подсветки синтаксиса

some_res = ['a', 'b', 'c', 'd'].map(getattr(obj.zip, _, None))
.filter(Non e).map(str).join(",")

some_res = ['a', 'b', 'c', 'd'].map(getattr(obj.zip, _, None))
.filter(None).map(str).join(",")

Если отвлечься от более удобной формы записи лямбды, то он все равно читается гораздо проще. Мне кажется дело в том, что он читается линейно слева направо, а не «вообще изнутри наружу, но местами слева направо», как читается код в питоне.

Это относится скорее не к функциональному стилю, а к процедурный vs ООП, но именно функциональный стиль провоцирует избавление от переменных и написание множества вложенных вызовов функций. Он как лакмусовая бумажка вскрывает плохую масштабируемость читаемости процедурных выражений:

Без подсветки синтаксиса

a(x, b(c(), 1, 4), 'd')
# vs
c().b(1, 4).a(x, 'd')

a(x, b(c(), 1, 4), 'd')
# vs
c().b(1, 4).a(x, 'd')

К сожалению питон чаще всего не позволяет писать сцепленными методами, поскольку бОльщая часть методов возвращает None вместо self (а именно все, которые модифицируют объект на месте), а map/filter — функции, а не методы.

Итого я для себя сменил идею с «функциональный код нечитаем» на «функциональный код, написанный в процедурном стиле, нечитаем».

Ссылки:
          ananthakumaran.in/2010/03/29/scala-underscore-magic.html

Исходники этого и других постов со скриптами лежат тут — github.com/koder-ua. При использовании их, пожалуйста, ссылайтесь на koder-ua.blogspot.com.

Автор: konstantin danilov

Контейнеры внедрения зависимостей для python

Начнем издалека — создание объекта инстанцированием класса плохо совместимо с идеями ООП. Они гласят, что код должен зависеть от интерфейсов, а не от реализаций. До тех пор пока на вход нашему коду приходят готовые объекты — все хорошо. Он будет с готовностью принимать любые типы, реализующие требуемый интерфейс, но как только мы начинаем создавать новые объекты ситуация меняется. Теперь код зависит от конкретного класса, что усложняет следующие задачи:

  • Изменение класса на другой, хоть и реализующий тот же интерфейс. Приходится вручную менять все точки инстанцирования, и, возможно, перекомпилировать код;
  • Выбор конкретного класса на основе внешних условий или точки инстанцирования;
  • Использование уже готового объекта — взятого из пула или какого то конкретного (синглетон);
  • Построение объекта с большим количеством зависимостей — приходиться передавать в точку конструирования все данные для построения множества взаимосвязанных объектов;
  • Не классическая проблема для ICC, но из той-же области:

Без подсветки синтаксиса

class A(object):
def __init__(self, val):
self.val = val

def __add__(self, val):
return A(self.val + val)

class B(A):
pass

print B(1) + 1 # <__main__.A object at 0x18877d0>

class A(object):
def __init__(self, val):
self.val = val

def __add__(self, val):
return A(self.val + val)

class B(A):
pass

print B(1) + 1 # <__main__.A object at 0x18877d0>

А хотелось бы получить экземпляр В.

Все эти проблемы связаны общей причиной — код делает работу, которую он делать не должен — инстанцирование конкретных классов. На самом деле чаще всего нам не нужен фиксированный класс. Нам нужен класс, предоставляющий определенный интерфейс. Нужно отвязаться от явного указания класса и передать его создание стороннему коду. Фактически мы хотим «виртуализовать» инстанцирование.

В самом простом случае можно воспользоваться фабричной функцией(ФФ). Если же мы хотим конфигурировать поведение ФФ, или сохранять состояние между вызовами (синглетон, пул объектов, etc), то логично сделать ФФ методом класса, в экземпляре которого будут храниться настройки. Такой класс может быть синглетоном(если конфигурация глобальная), или передаваться образом по цепочке вызовов во все точки, где нужно инстанцирование. Этот класс как раз и называется Inversion of Control Container (ICC дальше).

Для его использования нужно заменить прямое инстанцирование классов на вызов метода ICC. Параметрами метода будут требуемый интерфейс, и, возможно, контекст вызова и часть параметров для конструктора (последнее применяется редко). ICC возвращает готовый экземпляр. Конкретный класс для инстанцирования и параметры конструктора настраиваются програмно или берутся из конфигурационного файла.

Типичный пример — создание виртуальной машины в libvirt. Основная функция API принимает xml строку, описывающую виртуальную машину. Эта строка чаще всего берется вызывающим кодом из внешнего источника, потому как в большинстве случаев ему не важны подробности конфигурации для работы с VM соответственно и код создания можно унифицировать, а строку с конфигурацией использовать как черный ящик.

ICC также можно рассматривать как шаблон проектирования, объединяющий и унифицирующий другие порождающие шаблоны — ФФ, синглетон, и прочее.

Java и C# имеет различные реализации ICC (java spring, dagger) которые используются очень широко. Для питона же они практически не применяются. Сначала я покажу как написать pythonic ICC, а потом рассмотрю почему он не нужен. Написание своего связанно с тем, что по уже готовые пишутся людьми только что пришедшими с Java/C# и не отличаются питонистичностью.

Итак что можно хотеть от идеального ICC? Во-первых оставить пользовательский код почти без изменений. Во-вторых поддерживать возможность возвращать при инстанцировании целевого класса экземпляры другого класса, или определенный объект или результат вызова некоторой функции.

Итак был такой код:

Без подсветки синтаксиса

class Bee(object):
def __init__(self, x):
pass

class Cee(object):
def __init__(self, x):
pass

assert isinstance(Bee(1), Bee)

class Bee(object):
def __init__(self, x):
pass

class Cee(object):
def __init__(self, x):
pass

assert isinstance(Bee(1), Bee)

Мы хотим иметь возможность не меняя код инстанцирования Bee выбирать что именно будет получаться — экземпляр Bee или Cee. С позиции duck typing классы Bee и Cee реализуют один и тот-же интерфейс и взаимозаменяемы, хоть мы это и не декларируем явным наследованием.

В принципе инстанцирование можно и не менять, но тогда его поведение будет не совсем очевидным. С первого взгляда кажется, что мы инстанцируем обычный класс Bee, а в итоге получаем экземпляр другого класса, который к классу Bee никакого отношения не имеет. Т.е. isinstance(Bee(), Bee) == False. Поэтому немного изменим пример. Bee и Cee будут наследовать общий интерфейс IBee и именно этот интерфейс мы и будем инстанцировать.

Без подсветки синтаксиса

class IBee(IOCInterface):
def __init__(self, x):
pass

class Bee(IBee):
def __init__(self, x):
print "Bee.__init__ called"

class Cee(IBee):
def __init__(self, x):
print "Cee.__init__ called"

IBee.register(Bee)
assert isinstance(IBee(1), Bee)

IBee.register(Cee)
assert isinstance(IBee(1), Cee)

class IBee(IOCInterface):
def __init__(self, x):
pass

class Bee(IBee):
def __init__(self, x):
print "Bee.__init__ called"

class Cee(IBee):
def __init__(self, x):
print "Cee.__init__ called"

IBee.register(Bee)
assert isinstance(IBee(1), Bee)

IBee.register(Cee)
assert isinstance(IBee(1), Cee)

Что бы это работало нужно перехватить конструирование объекта типа IBee и вернуть что-мы-там-хотим. Для этого вспоминаем, что конструирование объекта в python выражается следующим псевдокодом:

Без подсветки синтаксиса

# obj = Cls(x, y) ==>

obj = Cls.__new__(Cls, x, y)
if isinstance(obj, Cls):
Cls.__init__(obj, x, y)

# obj = Cls(x, y) ==>

obj = Cls.__new__(Cls, x, y)
if isinstance(obj, Cls):
Cls.__init__(obj, x, y)

Т.е. Cls.__new__ возвращает пустой экземпляр типа Cls, Cls.__init__ наполняет его реальными данными. Очень похоже на operator new + конструктор в С++. Итак нам нужно перегрузить IBee.__new__ и возвращать из него наш объект.

Без подсветки синтаксиса

ioc = {}

class IOCInterface(object):
def __new__(cls, *args, **kwargs):
return ioc[cls](cls, *args, **kwargs)

@classmethod
def register(cls, impl):
factory = lambda ccls, *args, **kwargs:
super(IOCInterface, ccls).__new__(impl, *args, **kwargs)
cls.register_factory(factory)

@classmethod
def register_instance(cls, obj):
cls.register_factory(lambda *args, **kwargs: obj)

@classmethod
def register_factory(cls, func):
ioc[cls] = func

ioc = {}

class IOCInterface(object):
def __new__(cls, *args, **kwargs):
return ioc[cls](cls, *args, **kwargs)

@classmethod
def register(cls, impl):
factory = lambda ccls, *args, **kwargs:
super(IOCInterface, ccls).__new__(impl, *args, **kwargs)
cls.register_factory(factory)

@classmethod
def register_instance(cls, obj):
cls.register_factory(lambda *args, **kwargs: obj)

@classmethod
def register_factory(cls, func):
ioc[cls] = func

Немного пояснений. Класс IOCInterface будет базовым для всех интерфейсов. Переменная ioc будет хранить текущую конфигурацию — отображение интерфейса на фабричную функцию для этого интерфейса. Для простоты примера мы будем хранить конфигурацию в глобальной переменной. Перегруженный метод __new__ получает инстанцируемый класс первым параметром, а дальше идут параметры конструктора. Он берет зарегистрированную для этого класса фабричную функцию и создает новый объект с ее помощью. IOCInterface.register позволяет зарегистрировать класс для данного интерфейса. IOCInterface.register_instance — зарегистрировать синглетон. Для унификации они создают специальные фабричные функции.

Замечания:

  • Нельзя использовать cls.__new__ как фабричную функцию в IOCInterface.register, так как мы получим вечный цикл. Нужно «проскочить» IOCInterface в иерархии сcls;
  • Для классов с перегруженным __new__ нужно смотреть по ситуации;
  • Есть соблазн просто сохранять класс/синглетон в словарь и потом в __new__

делать что-то вида;

Без подсветки синтаксиса

def __new__(cls, *args, **kwargs):
obj = ioc[cls]
if isinstance(obj, type):
return obj(cls, *args, **kwargs)
elif type(obj, (types.FunctionType, types.LambdaType)):
return obj(cls, *args, **kwargs)
else:
return obj

def __new__(cls, *args, **kwargs):
obj = ioc[cls]
if isinstance(obj, type):
return obj(cls, *args, **kwargs)
elif type(obj, (types.FunctionType, types.LambdaType)):
return obj(cls, *args, **kwargs)
else:
return obj

Делать этого не стоит, хотя бы потому что так мы не сможем зареги

Устанавливаем дрова на сетевую карту Atheros AR9485

Прикупил себе сегодня новый бук взамен доблестно умершего. Моделька новая. Lenovo G500. Почитать о ней можно тут. Соответственно и железки новые. Не исключение и наша сетевуха. По умолчанию заработал тока Wi-Fi и локальная петля. Ethernet`а не было и в помине.

Открываем терминал и смотрим, что у нас внутри:
electrichp@electrichp-Lenovo-G500 ~ $ lspci -vv | grep Atheros
01:00.0 Ethernet controller: Atheros Communications Inc. Device 10a0 (rev 10)
02:00.0 Network controller: Atheros Communications Inc. AR9485 Wireless Network Adapter (rev 01)
После более чем трехчасовых поисков необходимого драйвера, последний был благополучно найден и прикручен. 
Нам необходимо скачать архив с названием compat-drivers-2013-03-26-u.tar.bz2 вот с этой странички https://www.kernel.org/pub/linux/kernel/projects/backports/2013/03/26/.
Далее открываем терминал, переходим в папку с загруженным и выполняем следующие команды:

tar -xvf compat-drivers-2013-03-26-u.tar.bz2
cd compat-drivers-2013-03-26-u
scripts/driver-select alx
make
sudo make install
sudo modprobe alx
После вышеперечисленных манипуляций все встает на свои места и пашет как надо.Это видно по выводу ifconfig:
electrichp@electrichp-Lenovo-G500 ~/Загрузки/compat-drivers-2013-03-26-u $ ifconfig
eth0 Link encap:Ethernet HWaddr 20:89:84:f6:ba:25
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Interrupt:16

lo Link encap:Локальная петля (Loopback)
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:3534 errors:0 dropped:0 overruns:0 frame:0
TX packets:3534 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:222967 (222.9 KB) TX bytes:222967 (222.9 KB)

wlan0 Link encap:Ethernet HWaddr 48:d2:24:a9:16:fd
inet addr:192.168.0.79 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: fe80::4ad2:24ff:fea9:16fd/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:18608 errors:0 dropped:0 overruns:0 frame:0
TX packets:11166 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:24376233 (24.3 MB) TX bytes:1306372 (1.3 MB)
Ну вот и все))) Кстати, имя драйвера, если кому пригодится: ath9k. Радуемся)))

Автор: Роман Дмитриевич

Python, processor affinity или как существенно ускорить некоторые программы, ничего не делая

Всем, кто увидел первую версию поста — цифры были кривые из-за turbo boost

Возьмем простой пример tcp клиента и сервера на python. Сервер создает пул из N потоков и ждет соединений с клиентом. Получив соединение передает его на обработку в пул. На каждом соединении сервер ждет от клиента строку данных и имитирует некую обработку. При получении 'byen' сервер завершает обработку клиента.

Клиент открывает N соединений с сервером и генерирует на них нагрузку. Общий объем нагрузки за один запуск клиента фиксирован.

Без подсветки синтаксиса

data = ' ' * 100 + 'x0A'
def client(th_count):
sockets = []
for i in range(th_count):
sock = socket.socket()

for cnt in range(3):
try:
sock.connect(host_port)
break
except socket.error:
if cnt == 2:
raise
time.sleep(0.1)

sockets.append(sock)

for i in range(NUM_PACKETS):
sock = random.choice(sockets)
sock.send(data)

for sock in sockets:
sock.send('byex0A')

data = ' ' * 100 + 'x0A'
def client(th_count):
sockets = []
for i in range(th_count):
sock = socket.socket()

for cnt in range(3):
try:
sock.connect(host_port)
break
except socket.error:
if cnt == 2:
raise
time.sleep(0.1)

sockets.append(sock)

for i in range(NUM_PACKETS):
sock = random.choice(sockets)
sock.send(data)

for sock in sockets:
sock.send('byex0A')

Без подсветки синтаксиса

def server(th_count):
def process_client(sock):
num = 0
while True:
msg = ""
while not msg.endswith('n'):
msg += sock.recv(1)

if msg == 'byen':
break

for i in range(serv_tout):
pass

num += 1

s = socket.socket()
s.bind(host_port)
s.listen(5)
with ThreadPoolExecutor(max_workers=th_count) as pool:
fts = []

for i in range(th_count):
sock,_ = s.accept()
fts.append(pool.submit(process_client, sock))

for ft in fts:
ft.result()

def server(th_count):
def process_client(sock):
num = 0
while True:
msg = ""
while not msg.endswith('n'):
msg += sock.recv(1)

if msg == 'byen':
break

for i in range(serv_tout):
pass

num += 1

s = socket.socket()
s.bind(host_port)
s.listen(5)
with ThreadPoolExecutor(max_workers=th_count) as pool:
fts = []

for i in range(th_count):
sock,_ = s.accept()
fts.append(pool.submit(process_client, sock))

for ft in fts:
ft.result()

Замеряем сколько времени нужно для одного прогона этой системы с N=4

Без подсветки синтаксиса

$ python mt_test.py client 4 & time python mt_test.py server 4

real 0m8.342s
user 0m7.789s
sys 0m6.587s

$ python mt_test.py client 4 & time python mt_test.py server 4

real 0m8.342s
user 0m7.789s
sys 0m6.587s

А теперь почти то же самое, но разрешим операционной системе исполнять все потоки сервера только на одном ядре из 8ми доступных

Без подсветки синтаксиса

$ python mt_test.py client 4 & time taskset 0x00000001 python mt_test.py server 4

real 0m4.663s
user 0m3.186s
sys 0m0.762s

$ python mt_test.py client 4 & time taskset 0x00000001 python mt_test.py server 4

real 0m4.663s
user 0m3.186s
sys 0m0.762s

Уличная магия в действии — многопоточная программа исполнилась в 2 раза быстрее, когда мы разрешили использовать только одно ядро процессора.

Почему такое получилось? Во-первых GIL — сколько бы потоков в питоне мы не создали, они всегда будут исполняться питоновский код только по очереди. Питон не позволяет двум потокам одного процесса одновременно исполнять свой байтокод.

Таким образом для этой программы(как и для 99% программ на питоне) никакого заметного ускорения от использования более одного ядра ожидать и не приходится. Все чисто питоновские программы конкурентны, но не параллельны. А конкурентной такой системе от изменения количества ядер в процессоре не холодно и не жарко (почти).

Почему же скорость исполнения падает, если использовать более одного ядра? Причин две:

  • Излишние переключения между потоками
  • Постоянная война за кеш с другими потоками в системе и друг с другом

Итак что происходит: пусть у нас есть два потока, один из которых(первый) сейчас обрабатывает принятые данные, а второй ожидает данных от сокета. Наконец второй поток получает данные и ОС готова продолжить его исполнение. Она смотрит на доступные ядра, видит что первое ядро занято первым потоком и запускает второй поток на исполнение на втором ядре. Второй поток запускается и первым делом пытается захватить GIL. Неудача — GIL захвачен первым потоком. Второй поток снова засыпает, ожидая освобождения GIL.

В итоге операционная система, которая понятия не имеет ни о каких GIL, сделала кучу лишней работы (переключение контекста достаточно дорогая операция). Правда заметная часть этой работы делалась вторым ядром, так что происходила параллельно и почти не мешала исполняться первому потоку. Почти — потому что второе ядро все равно занимало шину памяти. Ситуация становится хуже, если в системе есть HT — в этом случае второе ядро может делить с первым исполняемые блоки процессора и все эти лишние переключения будут серьезно замедлять исполнение первого потока.

Вторая проблема состоит в том, что второй поток переброшен на исполнение на второе ядро процессора. Когда первый поток освободит GIL
, то второй поток продолжит исполнение на втором ядре, потому что ОС знает, что кеши первого и второго уровня у каждого ядра свои и старается без причин не гонять потоки между ядрами. В итоге все имеющиеся потоки «размазываются» по доступным ядрам. Съедая в сумме 100% одного ядра, они превращают это в 12.5% на каждом из 8ми ядер. При этом в промежутках пока питоновские потоки ждут GIL на эти ядра вклиниваются другие потоки из системы, постоянно вытесняя наши данные из кеша.

В итоге питоновские потоки постоянно «бегают» по ядрам. Данные копируются в кеш и из кеша, а каждый кеш-промах стоит до тысяч тактов на обращение к RAM. Даже по меркам питона — серьезные нагрузки.

Выставив привязку к одному ядру мы убиваем сразу двух зайцев. Во-первых сокращаем количество переключений контекста, поскольку ОС будет заметно реже запустить на исполнение второй поток, если единственное доступное ему ядро сейчас занято. Во-вторых другие потоки не будут вклиниваться на это ядро, тем самым мы уменьшим интенсивность обмена данными между кешем и ОЗУ (питоновские потоки в одном процессе используют заметную часть данных совместно).

Итоги тестирования.

  • SUM — общее затраченное время
  • SYS — время, затраченное операционной системой
  • USR — время, затраченное в пользовательском режиме
  • XXX_AF — XXX в случае, если выставлена привязка к одному ядру
  • DIFF — отличие в процентах между XXX и XXX_AF

Все измерения сделаны на Core i7-2630QM@800MHz, python 2.7.5, x64, ubuntu 13.10 с усреднением по 7ми выборкам. Долгая война с turbo boost окончилась принудительным переводом процессора в режим минимальных частот.

    -------------------------------------------------------------------------
| Потоки | SUM SUM_AF %DIFF | SYS SYS_AF %DIFF | USR USR_AF %DIFF |
-------------------------------------------------------------------------
| 1 | 3.35 3.55 -5 | 0.54 0.52 4 | 2.78 3.03 -8 |
| 2 | 7.26 4.63 36 | 4.91 0.67 86 | 5.10 2.95 42 |
-------------------------------------------------------------------------
| 4 | 8.28 4.90 41 | 6.58 0.76 88 | 7.37 3.14 57 |
| 8 | 7.96 5.00 37 | 6.49 0.84 87 | 7.32 3.15 57 |
-------------------------------------------------------------------------
| 16 | 9.77 5.88 40 | 6.53 0.73 89 | 7.01 3.15 55 |
| 32 | 9.73 6.84 30 | 6.54 0.81 88 | 7.06 3.04 57 |
-------------------------------------------------------------------------

Прогон теста по VTune показывает, что после выставления привязки количество кеш промахов уменьшается примерно в 5 раз, а количество переключений контекста — в 40. В ходе экспериментов обнаружилась еще одна интересная вещь — при выставлении привязки к одному ядру более эффективно используется turbo boost, что тоже ускорит вашу программу, если больше никто не грузит систему. Для этого теста turbo boost был заблокирован.

Будет ли что-то подобное в других случаях? Хотя данная программа и обрабатывает данные, приходящие из сокета, но данные приходят быстрее, чем она может их обработать. Таким образом она является CPU bounded. Если программа будет в основном занята ожиданием данных, то выставления привязки к ядру даст меньше ускорения — ОС будет меньше перебрасывать потоки между ядрами. Чем выше нагрузка на процессор, тем больше будет выигрыш.

Когда мы можем получить замедление:

  • если в программе есть места, которые действительно параллельны, например часть работы делается С/С++ библиотекой, которая отпускает GIL
  • Или вы используете jython или ironpython
  • Если вы используете multiprocessing/ProcessPoolExecutor, которые запускают отдельные процессы и не имеют проблем с GIL. Привязка в линуксе наследуется потоками/процессами. Так что для дочерних процессов ее нужно или отменить, или выделить по своему ядру на каждый процесс.
  • В некоторых однопоточных системах, например при использовании gevent

P.S. В 3.3 поведение все то-же.

P.S.S. Нашел уже готовую статью про тоже самое.

Ссылки:
          habrahabr.ru/post/84629
          habrahabr.ru/post/141181
          vimeo.com/49718712
          stackoverflow.com/questions/868568/cpu-bound-and-i-o-bound
          ru.wikipedia.org/wiki/Hyper-threading

Исходники этого и других постов со скриптами лежат тут — github.com/koder-ua. При использовании их, пожалуйста, ссылайтесь на koder-ua.blogspot.com.

Автор: konstantin danilov

Дружим Linux Mint и Samsung Smart TV



Недавно приобрел в домашнее пользование Samsung Smart TV 5-ой серии. Так как смартфон был прикручен моментально через AllShare самсунговский и весьма успешно работает, было решено еще и нубук прикрутить. Путем выкуривания форумов и мануалов было решено ставить приложение MiniDLNA. Есть конечно еще несколько подобных софтин, но у всех свои затыки. Какая тупит, а какая русскую локаль не понимает. Хотя возможно все это из-за кривости моих рук. 
Итак, начнем-с пожалуй.




1. Установка

Как обычно, три варианта. Первый вариант через преславутый Менеджер программ. Второй — с терминала командой:
sudo apt-get install minidlna
Третий — через PPA следующей командой:
sudo add-apt-repository ppa:stedy6/stedy-minidna
sudo apt-get update
sudo apt-get install minidlna

2. Конфигурирование
Ну а тут уже веселее. Сам конфиг лежит тут: /etc/minidlna.conf.
Открываем из под рута любым методом, или как я через gedit:
sudo gedit /etc/minidlna.conf
Cмотрим, что там есть. Базовый файл с настройками имеет комментарии ко всем параметрам. Все довольно просто и понятно. Вносим лишь кастом-поправки, такие как пути до каталогов с медиаконтентом, имя сервера и так далее. Вот пример моего конфига (комменты переведены):

# порт для HTTP (подписи, SOAP, передача мультимедиа) траффика
port=8200

# сетевые интерфейсы для работы сервера, разделяйте запятыми
network_interface=wlan0

# укажите директории для сканирования.
# * можете у