Глобальная переменная: может ли ее значение измениться до того, как оно будет получено потоком? - PullRequest
3 голосов
/ 04 августа 2009

В следующем коде вы видите, что pickledList используется потоком и задается в глобальной области видимости.

Если переменная, которую использовал поток, была динамически установлена ​​где-то внизу в этом последнем цикле while, возможно ли, что его значение может измениться до того, как поток его использует? Как я могу динамически установить значение в цикле, отправить его в поток и убедиться, что , что его значение не изменится, прежде чем поток сможет его использовать?

import pickle
import Queue
import socket
import threading

someList = [ 1, 2, 7, 9, 0 ]
pickledList = pickle.dumps ( someList )

class ClientThread ( threading.Thread ):
   def run ( self ):
      while True:
         client = clientPool.get()
         if client != None:
            print 'Received connection:', client [ 1 ] [ 0 ]
            client [ 0 ].send ( pickledList )
            for x in xrange ( 10 ):
               print client [ 0 ].recv ( 1024 )
            client [ 0 ].close()
            print 'Closed connection:', client [ 1 ] [ 0 ]


clientPool = Queue.Queue ( 0 )

for x in xrange ( 2 ):
   ClientThread().start()

server = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
server.bind ( ( '', 2727 ) )
server.listen ( 5 )

while True:
   clientPool.put ( server.accept() )

РЕДАКТИРОВАТЬ:

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

from threading import Thread
class t ( Thread ):
    def run(self):
        print "(from thread) ",
        print i

for i in range(1, 50):    
    print i
    t().start()

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

1 Ответ

3 голосов
/ 04 августа 2009

Вариант 1: вы можете передавать аргументы в каждый поток, когда он создается:

ClientThread(arg1, arg2, kwarg1="three times!").start()

, в этом случае будет вызван ваш run метод:

run(arg1, arg2, kwarg1="three times!")

экземпляром Thread при вызове start(). Если вам нужно передать изменяемые объекты (диктанты, списки, экземпляры) в функцию, вы должны обязательно переназначить глобальную переменную, не редактировать ее на месте.

Вариант 2: вы можете установить переменную экземпляра для ваших ClientThread объектов:

myThread.setMyAttribute('new value')

С опцией 2 вам нужно опасаться условий гонки и т. Д. В зависимости от того, что делает метод. Использование Lock s всякий раз, когда вы пишете или читаете данные из / в поток, - это хорошая идея.

Вариант 3: захватить глобальный объект при первом вызове run и сохранить копию локально

run(self):
    localVar = globalVar # only for immutable types
    localList = globalList[:] # copy of a list
    localDict = globalDict.copy() # Warning! Shallow copy only!

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

Что касается обычно передаваемых переменных / значений, вы должны помнить с Python, что неизменяемые объекты (строки, числа, кортежи) передаются по значению , а изменяемые объекты (dicts, списки, экземпляры классов) передано по ссылке .

Следовательно, изменение строки, числа или кортежа не повлияет на экземпляры, ранее переданные этой переменной, однако изменение dict, списка или экземпляра подойдет. Повторное присвоение переменной другому объекту не повлияет на что-либо ранее, учитывая старое значение.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...