LINUX.ORG.RU

Python, отстрел ног, JS-way

 ,


1

3

Какой же болезненный отстрел

from time import sleep
import random
import threading

from Queue import Queue

class ThreadPool(object):

  def __init__(self, workers_count):
    self.queue = Queue()
    self.threads = []
    self.shutdown = False
    self.finalized = False

    for _ in range(0, workers_count):
      thread = threading.Thread(target=lambda: self.DoWork())
      thread.daemon = True
      thread.start()
      self.threads.append(thread)

  def Submit(self, task):
    if not self.finalized:
      self.queue.put(task)

  def DoWork(self):
    while not self.shutdown:
      task = self.queue.get()
      try:
        task()
      except Exception as e:
        print e
      self.queue.task_done()

  def FinalizeAndWaitCompletion(self):
    self.finalized = True
    self.queue.join()

def DoWork(n):
  print "Doing work "+str(n)+" on "+str(threading.current_thread().ident)
  sleep(random.randrange(100, 10000)/1000.0)
  print "Done work "+str(n)+" on "+str(threading.current_thread().ident)


def main():
  tp = ThreadPool(10)

  for i in range(0, 30):
    tp.Submit(lambda: DoWork(i))

  tp.FinalizeAndWaitCompletion()

if __name__ == '__main__':
  main()

Можете атомарности и локи не тыкать, с этим все норм, не нужно.

Ладно, добавлю вывод, а то тут не все запускать будут

Doing work 3 on 140046287099648
Doing work 3 on 140046295492352
Doing work 6 on 140046278706944
Doing work 6 on 140046057334528
Doing work 6 on 140046065727232
Doing work 7 on 140046048941824
Doing work 8 on 140046040549120
Doing work 9 on 140046032156416
Doing work 10 on 140046023763712
Doing work 11 on 140046015371008
Done work 8 on 140046040549120
Doing work 14 on 140046040549120
Done work 11 on 140046015371008
Doing work 14 on 140046015371008
Done work 14 on 140046040549120
Doing work 14 on 140046040549120
Done work 6 on 140046278706944
Doing work 14 on 140046278706944
Done work 3 on 140046287099648
Doing work 14 on 140046287099648
Done work 6 on 140046057334528
Done work 7 on 140046048941824
Done work 6 on 140046065727232
Done work 10 on 140046023763712
Done work 14 on 140046287099648
Done work 14 on 140046040549120
Done work 3 on 140046295492352
Done work 9 on 140046032156416
Done work 14 on 140046015371008
Done work 14 on 140046278706944
★★★★★

Последнее исправление: vertexua (всего исправлений: 3)

установи интерпретатор или пользуйся онлайн сервисами

$ python run.py
Traceback (most recent call last):
  File "run.py", line 53, in <module>
    app.run()
NameError: name 'app' is not defined

anonymous
()
Ответ на: комментарий от anonymous

Пофикшено, криво копипастил

vertexua ★★★★★
() автор топика

Любой, кто использует для имен методов конвенцию вроде DoWork, должен страдать. И чем больше он страдает, тем лучше для человечества.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

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

vertexua ★★★★★
() автор топика
Ответ на: комментарий от vertexua

Там был еще метод, который его присваивает

Но сейчас-то его нет.

По-моему, у тебя стандартная ошибка с лямбдой в цикле, еще я не уверен, что ты правильно используешь очередь. Короче, колись, в чем проблема.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

стандартная ошибка с лямбдой в цикле

Оно, правда говно? А вот когда такое в более сложном коде, а не в этой игрушке, то хочется плакать кровавыми слезами. И даже фиксить не (function(i){...})(i) а чуть по другому

И чтобы чуть уменьшить вероятность отстрела с пользовательской стороны лучше сделать так

  def Submit(self, func, *args):
    if not self.finalized:
      self.queue.put(lambda: func(*args))
vertexua ★★★★★
() автор топика
Последнее исправление: vertexua (всего исправлений: 3)
Ответ на: комментарий от vertexua

Оно, правда говно?

Это общеизвестный wart же. Те, кто нарвался на это однажды, запоминают навегда.

А вот когда такое в более сложном коде

Вот поэтому рулит инкрементальная разработка и mq.

tailgunner ★★★★★
()
Ответ на: комментарий от vertexua

И чтобы чуть уменьшить вероятность отстрела с пользовательской стороны лучше сделать так

Сомнительный фикс.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Это общеизвестный wart же. Те, кто нарвался на это однажды, запоминают навегда.

Нарывался в JS, но с JS все понятно. Почему-то не ожидал тут такого шлака. Хотя понятно в принципе из-за поведения scope в Python что все так же хреново

mq

Я тебя умоляю...

vertexua ★★★★★
() автор топика
Ответ на: комментарий от tailgunner

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

vertexua ★★★★★
() автор топика
Последнее исправление: vertexua (всего исправлений: 1)
Ответ на: комментарий от vertexua

Ну я так понял что неотстрельного кода вроде не получится сделать

Ы?

for i in range(30):
  tp.Submit(lambda x = i: DoWork(x))

Пользователь может хотеть шарить стейт. Что предлагаешь? mq?

Хм. Что в твоем понимании MQ? %)

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Ы?

Я имел ввиду что даже тупой пользователь вроде меня чтобы не запутался.

Что в твоем понимании MQ

Очевидно что-то не то. А ты о чем?

vertexua ★★★★★
() автор топика
Ответ на: комментарий от vertexua

Я имел ввиду что даже тупой пользователь вроде меня чтобы не запутался.

«Сделайте систему, которой может пользоваться даже дурак, и только дурак будет ей пользоваться» (ц)

Тем более, что возможность

tp.Submit(lambda i: DoWork(x), ())

остается. Напомнить в документации метода о wart, и хватит.

А ты о чем?

http://mercurial.selenic.com/wiki/MqTutorial

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)

отстрел ног

Яйца хоть целы?

ritsufag ★★★★★
()
import functools

for i in range(0, 30):
    tp.Submit(functools.partial(DoWork, i))

# UPD:

и вообще говорю на будущее — если изучаешь Пайтон, то первое что нужно выучить это модули: [itertools], [functools], [asyncio]

user_id_68054 ★★★★★
()
Последнее исправление: user_id_68054 (всего исправлений: 2)
Ответ на: комментарий от user_id_68054

если изучаешь Пайтон, то первое что нужно выучить это модули: [itertools], [functools], [asyncio]

Первое? Глупости. И даже потом - всё зависит от того, чем занимаешься. Мне asyncio ни разу не понадобился за 10+ лет %) Полезность itertools тоже преувеличена.

tailgunner ★★★★★
()

concurrent.futures.ThreadPoolExecutor

//тред и код не читал.

risenshnobel ★★★
()
[[lambda x, i=i: x*i for i in (1,2,3)][i](1) for i in (0,1,2)]
aedeph_ ★★
()
Ответ на: комментарий от Manhunt

Все норм. Не вижу проблем. С помощью ThreadPool контролирую количество процессов на С++ (системных утилит), которые обрабатывают задачи. Можно через семафор и счетчик, но через пул чуть удобнее.

Плюс часто из таких пулов потоков вызывается код С++ напрямую и перед этим отпускается GIL

vertexua ★★★★★
() автор топика
Последнее исправление: vertexua (всего исправлений: 2)
Ответ на: комментарий от vertexua

А можешь пояснить, в чем именно проблема? Про особенности использования, например, счетчиков цикла в замыканиях на JS я знаю, но ведь здесь внутри лямбды ничего, кроме self, не захватывается.

anonymous
()
Ответ на: комментарий от vertexua

Я бы с радостью, но оно Python 3
asyncio

специально его указал — чтобы вы не брали в руки эту гадасть python-2.X :) .. ну а если и брали бы — то сидели бы тихонько (со стыдливым выражением лица) а не заявляли бы на весь форум о том что якобы Пайтон причинил вам боль :-)

не нравится asyncio ? ну возьми тогда concurrent.futures.ThreadPoolExecutor (как уже заметили выше) .. ой(!) он же тоже для python-3.X :-D

user_id_68054 ★★★★★
()
Последнее исправление: user_id_68054 (всего исправлений: 3)
Ответ на: комментарий от anonymous

Ох, что-то я протупил: не на ту лямбду смотрел. Вопрос снимается.

anonymous
()

[thread.daemon = False], а потом joinиться в threads. tp.Submit что там делает, и зачем он именно там и в таком виде - хрен пойми, разве так пишут?)

menangen ★★★★★
()
Ответ на: комментарий от user_id_68054

сидели бы тихонько (со стыдливым выражением лица) а не заявляли бы на весь форум о том что якобы Пайтон причинил вам боль :-)

Поведение lambda в Python 3 не изменилось. Так что это любителям Python 3 лучше бы помолчать со стыдливым выражением лица.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Поведение lambda в Python 3 не изменилось. Так что это любителям Python 3 лучше бы помолчать со стыдливым выражением лица.

ну смотри:

https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures....

видишь параметры fn, *args, **kwargs ?

тебе ясно почему эти параметры не дадут так просто выстрелить себе в ногу?

а теперь сможешь дать мне такую же ссылку , но для Python-2.X ? не можешь? ну вот это и называется боль от использования мамонтовского говна :-)

по сути — весь Python-2.X — это и есть сборник того как стрелять себе в ноги.. (чтобы эту стрельбу в ноги исключить по максимому — как раз и пришлось отказаться от обратной совместимости... а чего в Python-2.X только стоит взаимодействие между байтоврой строкой и юникодной строкой)

user_id_68054 ★★★★★
()
Последнее исправление: user_id_68054 (всего исправлений: 4)
Ответ на: комментарий от user_id_68054

https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures....

Ты до сих пор не понял, что дело вообще не конкурентности? Печально.

тебе ясно почему эти параметры не дадут так просто выстрелить себе в ногу?

Нет. Ты видишь фрагмент кода:

  for i in range(0, 30):
    tp.Submit(lambda: DoWork(i))

? Его поведение одинаково в Python 2 и Python 3.

по сути — весь Python-2.X — это и есть сборник того как стрелять себе в ноги..

По сути Python3 == Python2 + несколько несовместимых фишек.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

? Его поведение одинаково в Python 2 и Python 3.

ну это да.. и пользователям python-2 повезло что у них есть (как и у пользователей python-3) — functools.partial(..)

просто какой шанс что пользователь python-3 тоже наступет на эту грабельку? ведь ему не пришлось бы городить этот класс ThreadPool вручную :-)

ну или вот — возьми [loop.run_in_executor(..)] .. тут тоже есть параметр *args

user_id_68054 ★★★★★
()
Последнее исправление: user_id_68054 (всего исправлений: 1)
Ответ на: комментарий от user_id_68054

Хватит вам спорить. Ну не поддерживаются нужные либы мне, а именно clang. Костыльные поделки на гитхабе с последним коммитом 2 года назад не в счет

vertexua ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.