【问题标题】:Not sure if I should use threading or not? [closed]不确定我是否应该使用线程? [关闭]
【发布时间】:2019-06-19 23:22:00
【问题描述】:

我会尽量让我想做的事情尽可能简单。

我有两个班级ClassAClassB

ClassA 有一个实例方法,其中包含一个“无限”运行并收集数据的 while 循环。 ClassA 也传递了ClassB 的实例。在ClassA 收集这些数据的同时,它也在检查传入的数据以查看是否已接收到某个信号。如果收到信号,则调用ClassB 中的实例方法。

考虑以下主程序驱动:

from class_a import ClassA
from class_b import ClassB

database_connection = MongoDB #purely example
class_b = ClassB(database_connection)
class_a = ClassA(class_b)

然后是课程:

Class class_a:

    def __init__(self, class_b):
        self.class_b

    def collect_data(self):
        while True:
            data = receiver()
            if (signal in data):
                self.class_b.send_data_to_database(data)

Class class_b:

    def __init__(self, database):
        self.database = database

    def convert_data(self, data):
        return data + 1

    def send_data_to_database(data):
        converted_data = convert_data(data)
        self.database.send(converted_data)

现在这是我的问题。我应该在 B 类中为“send_data_to_database()”实例方法创建一个线程吗?我的想法是,可能产生一个线程只是为了处理将数据发送到数据库,这将比没有线程化的实例方法更快。我的想法在这里错了吗?我对线程的了解有限。最终,我只是想找到在 A 类识别到数据中有信号时将数据发送到数据库的最快方法。感谢所有提前回复的人。

【问题讨论】:

  • 线程意味着并发 - 即同时执行多个操作。您的代码完全是顺序的,一个接一个的动作:... -> receive -> check -> send -> receive -> ...。将 single 动作卸载到线程,例如发送,通常是不值得的 - 启动线程比直接执行操作需要更长的时间。
  • 如果数据中没有信号,收集到的数据会变成什么? A 级是在数据收集运行之间休眠,还是尽可能快地转动?是否存在他落后的现实风险,还是他可以自己花时间收集数据?除了这个数据收集部分,应用程序的其余部分在做什么?还是这个?
  • @bigh_29 没有信号的数据,被省略。 ClassA 在数据收集运行之间不休眠。为简单起见,这几乎就是应用程序(除了正在处理的数据)。数据收集落后不存在重大风险;我主要关心的是能够在接收到该信号后尽快发送数据。
  • 如果没有数据收集落后的风险,这里就不需要线程。当然不是每次要写入数据库时​​都打开一个线程并关闭它,这样会更慢。如果担心数据收集可能会落后,并且您希望 while 循环即使在发生写入时也能继续,那么我将永久打开一个线程,并使用第二个 while 循环监视队列(来自标准 Python 库)。将数据库写入请求发送到队列,并在第一个线程继续时让第二个线程处理它们。
  • @KyleDeGennaro 进程甚至比线程更昂贵。如果你没有任何事情可以并发做,那么并发做事情是没有意义的。如果您不知道您是否同时有任何事情要做,我们也无法告诉您。归根结底,并发是权衡成本与收益,而您两者都没有定义。转换需要多长时间?发送需要多长时间?接收需要多长时间?在出现问题之前,发送可以延迟接收多长时间?您是否受 CPU 或 I/O 限制?等等……

标签: python python-3.x multithreading python-multithreading


【解决方案1】:

如果其中任何一个为真,我会使用线程:

  • B 中的阻塞 I/O 数据库调用会对 A 的能力产生负面影响 及时收集数据。
  • 这两个数据收集部分一起会对应用其他部分的响应能力产生负面影响(想想无响应的 GUI)

如果两个条件都不成立,那么单线程应用程序的麻烦就会少很多。

如果您确实使用线程,请考虑使用Queue for concurrency。 A 类可以将数据发布到 B 类正在等待的队列中。这是我的意思的基本代码示例:

from queue import Queue
from threading import Thread, Event

class class_a:
    def __init__(self, queue):
        self.queue = queue
        self.thread = Thread(target=self.collect_data)
        self.thread.start()

    def collect_data(self):
        for data in range(1000):
            if data % 3 == 0:
                print(f'Thread A sending {data} to queue')
                self.queue.put(data)
            else:
                print(f'Thread A discarding {data}')

class class_b:
    def __init__(self):
        self.queue = Queue()
        self.thread = Thread(target=self.process_data)
        self.thread.daemon = True
        self.thread.start()

    def process_data(self):
        while True:
            data = self.queue.get()
            print(f'Thread B received {data} from queue')

b = class_b()
a = class_a(b.queue)

最后,每当您考虑在 python 中使用并行性时,您必须询问multiprocessing 是否比多线程更有意义。当 CPU 计算而不是文件或网络 I/O 成为应用程序性能的限制因素时,多处理是更好的选择。根据您提供的信息,我认为多处理不适合您的项目。

【讨论】:

  • 我明白了。如果实施队列,也许一定会浪费时间?因为现在,ClassA 将数据发送到队列,而ClassB 进行侦听。与我原来的例子相比,这不是增加了从ClassAClassB 获取数据的额外步骤吗?
  • 我完全同意使用队列的建议。这样,就消除了为数据中每次出现信号而启动线程的开销。
  • 也许我的解释有问题;我不打算在数据中每次出现信号时启动线程。只需一个线程来监听该信号,然后通过 HTTP 向数据库发送请求;线程化发送 HTTP 请求的方法会比没有更快吗?还是因为所有事情都必须按顺序发生,所以这样做没有显着差异(并且可能会浪费内存)?
  • @KyleDeGennaro,粘贴了一个代码示例以便更好地解释。 B 类为应用程序的生命周期生成一个线程。 Queue 是一个线程向另一个线程发送数据的好方法。您可能希望将队列封装在 B 上的辅助方法后面。取决于您是否希望 A 类知道 B 类的实例,或者它是否应该知道共享的 Q 实例。无论哪种方式,队列都在处理两者之间的通信。
  • 感谢您的详细回复。很有帮助!
猜你喜欢
  • 2016-07-31
  • 1970-01-01
  • 1970-01-01
  • 2012-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-10
  • 1970-01-01
相关资源
最近更新 更多