LINUX.ORG.RU

python ограничить область видимости для import (или шаринг переменных между модулями)

 , ,


1

1

Дано: a.py - главный модуль b.py - движок shared.py - файл с переменными

Вот так сейчас выглядит код: a.py:

import b
import shared

shared.shared_var = 1

b.engine()

b.py

import shared


def engine():
    print("работаем с: {}".format(shared.shared_var))

shared.py

shared_var = 0

В чём проблема: a.py вызывается многопоточно, и в итоге начинается каша - переменные внутри shared.py становятся общими для всех потоков.

Мне надо так сделать чтобы у каждого потока была своя область видимости.

Что я пробовал: - Делать import внутри функции def, итог - всё равно тоже самое - Делать не import, а from shared import * - так возникает геморой с тем что вызывая это в a.py я не могу в b.py передать контекст - Тупо всё в функции сувать (все переменные), в итоге на каждый чих мне надо портянку переменных сувать, код раздувается

В общем очень надо сделать так чтобы функции отдельно, а переменные отдельно, и у каждого потока своя область видимости переменных.

PS: вот это уже читал http://ru.stackoverflow.com/questions/358/Глобальные-переменные-в-python



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

у каждого потока была своя область видимости.

Ну так вся суть потоков - это общая область видимости. Возьми лучше многопроцессность, заодно и от GIL избавишься.

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

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

rubro
() автор топика

Тупо всё в функции сувать (все переменные), в итоге на каждый чих мне надо портянку переменных сувать, код раздувается

Запихни их в объект.

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

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

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

красивое решение - не делать централизированное хранилище и хранить все по месту, если данные все-равно не пересекаюстя

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

Я не проверял это решение, идея была сделать так, «import shared» вставлять в a.py и в b.py, а внутри там сделать словарь и данные идентифицировать по ключу, имя которого - имя потока.

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

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

И вот как это сделать? Условно говоря мне надо подать на входе числа от 1 до 100, затем сделать так чтобы каждый поток взял установил внутри себя переменной значение a=число и эту переменную «a» мне надо видеть из других импортированных файлов, чтобы не было пересечения между потоками как сейчас это происходит

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

Всё равно как-то геморойно смотрится, не могли бы вы пожалуйста вашу схему правильной архитектуры расписать? Вот на примере этой задачи: python ограничить область видимости для import (или шаринг переменных между модулями) (комментарий)

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

ну имя потока это что-то что ты сам задаешь? а одни и те же потоки выполняют разный код, но разный код зависит от своих переменных? ну и используй hash(my_func) как ключ в словаре, это если my_func1 использует ключ 1, my_func2 ключ 2 и так далее. можно хоть объект пустой создавать в коде и его использовать: key = hash(object()).

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

имя потока - нет я брал его вот таким образом: http://stackoverflow.com/questions/17707775/get-thread-id-or-name-in-python-2-6 и у меня получались дубли

а одни и те же потоки выполняют разный код, но разный код зависит от своих переменных?

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

вашу идею пока что понять не удаётся(

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

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

Чтобы такого не было, каждый поток перед изменением объекта блокирует его для изменения другими потоками.

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

Понял идею, всё равно какой-то говнокод получается - есть варианты без блоков, чую есть решение где-то рядом, не могу его найти

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

threading.local()

я смотрю тут id снова одинаковый, на 10 потоков и 10 заданий у меня вышло 5 дублей

Ты использовал threading.local, и разные потоки меняли значение друг у друга? Покажи код.

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

Ребят попробую попроще выразить суть задачи, может так проще будет помочь.

Даны файлы a.py, b.py, c.py, d.py

a.py многопоточно запускает функцию внутри b.py, а та вызывает в свою очередь функции из c.py, а та из d.py

На уровне a.py присваивается переменная test = «что-то_там», присваивание происходит внутри потока, у каждого потока своё значение переменной

Вопрос: как мне видеть переменную test внутри файлов b, c, d?

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

да, вот код main.py:

from queue import *
from threading import Thread, local


def doo2():
    task = q_src.get()  # task_0
    print(local())
    q_src.task_done()

q_src = Queue(maxsize=0)
num_threads = 10


# функция обработки потоков
def do_stuff(q_src):
    while True:
        doo2()

# запуск потоков
for i in range(num_threads):
  worker = Thread(target=do_stuff, args=(q_src,))
  worker.setDaemon(True)
  worker.start()

# закидываем задания на исполнение
for x in range(10):
  q_src.put("task_" + str(x))


q_src.join()
print("работа выполнена")

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

Что я должен был увидеть из этого примера? Или ты не понимаешь, как используется threading.local?

Это объект, значения полей которого для всех разные — такие, какие они сохранили. Как указано в документации:

mydata = threading.local()
mydata.x = 1
Если другой тред сделает mydata.x = 2 в том же объекте, то первый тред продолжит видеть 1, а второй будет видеть 2.

В целом, систему надо менять. Это «общая» переменная в a.py должна быть не глобальной в модуле, а полем объекта, а всё, что к ней обращается, либо методами этого объекта, либо функциями, принимающими этот объект.

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

Я в питоне очень слабоват, сперва не так понял locals(). Огромное спасибо за разъяснения! Только их пока что мне не удаётся к делу пришить, квалификация моя слабовата. Не сочтите за наглость, не могли бы вы пожалуйста запилить небольшой пример как реализовать описанную мной задачу? На базе того кода что я выложил

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

Тут вычитал что юзать не рекомендуют

Там написано только, что вот так делать нельзя:

for key in mydict:
    mydict["новый ключ"] = "что-нибудь"

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

Типовое использование - это поменять строку на новую, добавив к исходной что-то новое.

Там много разных переменных, словари, списки и.т.д., можно добавить в список элемент, соответственно в других местах я должен увидеть изменённый список.

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

мог бы ты реализовать свою задачу на любом другом языке? у тебя не с питоном или словарями проблема, а в дизайне. defective by design and overcomplicated. можем начать с одного модуля без потоков и процессов, чтоб понять какие ты делаешь вычисления? тут все очень зависит, и бывает что локи сводят на нет приимущества. может ты делаешь тестовое, но тогда сам разберись.

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

возможно, поще всего тебе будет использовать готовое решение вроде редиски или любого in-memory хранилища, реализованного в самом питоне, посмотри примеры их использования - ты делаешь то же самое

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

Типовое использование - это поменять строку на новую, добавив к исходной что-то новое.

Я говорю, что в переменных-то хранится?

Там много разных переменных, словари, списки и.т.д., можно добавить в список элемент, соответственно в других местах я должен увидеть изменённый список.

Ну например? Я не могу понять, почему они должны быть привязаны к потокам, а не к задачам.

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

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

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

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

Делаю не тестовое.

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

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

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

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

асинхронный ввод-вывод (сетевой), коллбеки, корутины, для очереди задач лучше все-таки использовать какое-то хранилище, т.к. задачи скорее всего придется добавлять в очередь из воркеров для балансировки

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

Каждый поток запускает функцию и передаёт ей задание. Функция берёт из задания сайт и данные к нему, и идёт с ним работать.

Всё было хорошо пока код был в 1 файле, а мне надо всё по уму разделить - движок отдельно, то что на сайте делаю - отдельно, состояние работы текущего потока - отдельно. Так проще работать.

Если не то объяснил - дайте знать пожалуйста, по другому напишу.

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

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

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

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

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

Я и взял готовую разработку, проблема то не на уровне работы с сайтом

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

дело в том что это каша в голове, если проблема только в том что потоки «затирают» то выбери другую схему именования - по урлу задачи, например.

не пойму чем один файл принципиально от нескольких отличается.

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