【问题标题】:why are my python threads blocking each other为什么我的 python 线程互相阻塞
【发布时间】:2014-10-12 00:07:32
【问题描述】:

我目前的困境是我试图让一个阻塞的网络服务脚本成为非阻塞的,以允许在任何时候进行多个下载,但目前它会挂起并等待第一个下载完成,然后再开始第二个.在你不遗余力地投票之前,因为答案很可恶,请知道这是我的第一个 python 脚本,我是自学的。

在下面的示例中,我只发布了一个“ConnectionProcesser”,因为它们都包含相同的代码 如果您需要更多代码,请询问

脚本有3个依赖项

import socket  # Networking support
import signal  # Signal support (server shutdown on signal receive)
import threading #to make the thing run more than one at a time

请注意,脚本已经过编辑,缺少相当多的代码,但我认为这与问题无关。

 def ConnectionProcessorC(self):
     connC, AddressC = self.socket.accept()
     print("C Got connection from:", AddressC)
     DataRecivedC = connC.recv(1024) #receive data from client
     DataRecivedC = bytes.decode(DataRecivedC) #decode it to string
     print(DataRecivedC)
     RequestMethod = DataRecivedC.split(' ')[0]
     print ("C Method: ", RequestMethod)
     if (RequestMethod == 'GET') | (RequestMethod == 'HEAD'):
         Response_Headers = 'HTTP/1.1 200 OK\n'
        # Current_Date = time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())
        # Response_Headers += 'Date: ' + current_date +'\n'
         Response_Headers += 'Server: Moes-Python-Server\n'
         Response_Headers += 'Connection: close\n\n'  # signal that the conection wil be closed after complting the request
         Server_Response =  Response_Headers.encode() # return headers for GET and HEAD
         file_handler = open('/usr/share/nginx/html/100mb.dump','rb')
         Response_Content = file_handler.read() # read file content
         file_handler.close()
         URL=DataRecivedC.split(' ')
         URL = URL[1] # get 2nd element
         #Response_Content="<html><body><p>Charlie TEStin this stuff yehURL:"+URL+"</p></body></html>"
         Server_Response +=  Response_Content 

         connC.send(Server_Response)
         print ("C Closing connection with client")
     else:
         print("C Unknown HTTP request method:", RequestMethod)

     connC.close()
     return 
 def Distrabuteconnections(self):
     A=0
     """ Main loop awaiting connections """
     while True:
         print ("Awaiting New connection")
         self.socket.listen(10) # maximum number of queued connections #changed to 1 from 3 to try and prevent waiting after closing for ther que to clean up 

         if (A==0):
             ConnectionProcessorA = threading.Thread(target=self.ConnectionProcessorA())
             ConnectionProcessorA.start()
             A=1
         elif (A==1):
             ConnectionProcessorB = threading.Thread(target=self.ConnectionProcessorB())
             ConnectionProcessorB.start()
             A=2
         else:
             ConnectionProcessorC = threading.Thread(target=self.ConnectionProcessorC())
             ConnectionProcessorC.start()
             A=0

我认为可以通过将 while true 更改为循环 3 次而不是 1 次的东西来解决问题。

【问题讨论】:

  • 从线程切换到子进程应该可以解决它
  • 但是为什么我需要子流程是有原因的吗?他们跑的不是更慢吗?
  • 子进程可能需要更长的时间才能启动并且具有更高的内存占用,但没有理由让它们变慢。原因是 GIL,它似乎会干扰线程。这不会发生在子流程中。
  • 不会影响线程之间共享的全局变量你知道像我这样的人可以从哪里开始将其转换为子进程吗?一些链接或需要做什么的简短示例会很好,我认为我仍然可以和朋友一起做这个,所以我将保留这个问题并希望有人提出解决方案
  • 仅供参考,对于以后遇到这个问题的人来说,这里的问题与 GIL 无关。

标签: python multithreading while-loop


【解决方案1】:

您应该传递对您希望在线程中启动的方法的引用。相反,您正在调用线程,并将从该方法返回的数据传递给 threading.Thread() 调用。

简而言之,您的代码应该变成:

     if (A==0):
         ConnectionProcessorA = threading.Thread(target=self.ConnectionProcessorA)
         ConnectionProcessorA.start()
         A=1
     elif (A==1):
         ConnectionProcessorB = threading.Thread(target=self.ConnectionProcessorB)
         ConnectionProcessorB.start()
         A=2
     else:
         ConnectionProcessorC = threading.Thread(target=self.ConnectionProcessorC)
         ConnectionProcessorC.start()
         A=0

注意self.ConnectionProcessorA 等后面的括号被删除。这传递了对在线程中启动方法的引用,线程模块将调用它自己。

注意,建议存储对您创建的线程的引用,这样它就不会被垃圾收集。因此,我建议您的代码变为:

     if (A==0):
         self.cpa_thread= threading.Thread(target=self.ConnectionProcessorA)
         self.cpa_thread.start()
         A=1
     elif (A==1):
         self.cpb_thread= threading.Thread(target=self.ConnectionProcessorB)
         self.cpb_thread.start()
         A=2
     else:
         self.cpc_thread= threading.Thread(target=self.ConnectionProcessorC)
         self.cpc_thread.start()
         A=0

【讨论】:

  • 我尝试了你的代码,它所做的只是一遍又一遍地运行 ConnectionProcessorA,所以我无法测试它是否有效
  • 我认为我需要做的是删除 while true 并在创建连接时用线程内部的调用替换它,这样脚本就不会像现在一样继续创建线程
  • 我本来希望所有 3 个线程仍然运行,但是是的,每次建立连接时最好只生成一个线程。您可能会在主线程中调用socket.accept(),并将connXAddressX 变量传递给线程。如果您在更改程序架构方面需要帮助,最好发布一个新问题,并附上一个关于您现在正在做什么的minimilistic working example,这样人们就可以实际运行一些代码来模拟您所做的事情正在做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-11
  • 2011-07-04
  • 1970-01-01
  • 1970-01-01
  • 2021-08-29
  • 2021-11-12
相关资源
最近更新 更多