如何在线程中修改列表?

1 投票
1 回答
2150 浏览
提问于 2025-04-17 20:59

我需要在一个 list 的末尾添加一些元素,这个操作是在一个线程中进行的。

这是我的代码:

def go():
  while queueCommand.qsize() > 0:
      command = queueCommand.get(False)
      res = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None, shell=True)
      output = res.communicate()
      output = str(output)
      star = output.find("address") + 8
      en = output.find(",")
      ip = output[star:en-3]  
      alist.append(ip)  #<================== her i use the liste

if __name__ == '__main__':      
  with open ("icq.txt","r") as myfile:
    text = myfile.read()
  end = 0
  alist = []
  queueCommand = Queue.Queue()
  while True:
    start = text.find("href=") + 13
    if start == 12:
      break
    end = text.find("/",start)
    if text[start:end].find("icq.com") != -1:
      hostname="host "+ text[start:end]
      queueCommand.put(hostname) 
    text = text[end:len(text)]  

  for i in range(10):   
    threading.Thread(target=go,args=(alist)).start() #<====== i give the list as argument

  print alist 

最后的打印语句显示的是一个空列表,[]。有什么想法吗?

1 个回答

2

你遇到了一些问题。

  1. 你把 alist 作为参数传入,但其实你需要把它作为一个元组传递,看起来你是想这么做的,但一个只有一个元素的元组应该是这样写的 (alist,)。现在你只是用了全局的 alist,这可能不是你想要的。

  2. 你的 go 方法并不期待有参数(也就是 alist)。

  3. 为了确保线程安全,我认为你需要使用某种信号量、互斥锁或锁机制。线程模块里有一个 Lock 的实现,你可以用它来限制在添加元素到 alist 时的访问。

  4. 最重要的是,你没有等线程完成就打印结果。要等线程完成,你需要在线程上调用 .join()

我可能会选择使用另一个队列实例来存放结果,这样在所有线程完成后,你可以从队列中读取所有结果来构建你的列表。

这是你代码的一个更新版本(可以正常工作的)。就像我说的,我可能会选择使用队列,而且自从我转向使用 eventlet/gevent 后,我对线程模块的使用不多……所以我提供的内容可能还有改进的空间。

import threading
import Queue
import subprocess

lock = threading.Lock()

def go(alist):
  while queueCommand.qsize() > 0:
      command = queueCommand.get(False)
      res = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None, shell=True)
      output = res.communicate()
      output = str(output)
      star = output.find("address") + 8
      en = output.find(",")
      ip = output[star:en-3]
      lock.acquire()
      alist.append(ip)  #<================== her i use the liste
      lock.release()

def foo(alist):
    alist.append("bar")

if __name__ == '__main__':
  with open ("icq.txt","r") as myfile:
    text = myfile.read()
  end = 0
  alist = []
  queueCommand = Queue.Queue()
  while True:
    start = text.find("href=") + 13
    if start == 12:
      break
    end = text.find("/",start)
    if text[start:end].find("icq.com") != -1:
      hostname="host "+ text[start:end]
      queueCommand.put(hostname)
    text = text[end:len(text)]

  threads = []
  for i in range(10):
    thread = threading.Thread(target=go,args=(alist,)) #<====== i give the list as argument)
    thread.start()
    threads.append(thread)
  for thread in threads:
    thread.join()

  print alist

撰写回答