python - 如何从进程或线程实例返回值?

标签 python multithreading multiprocessing python-multiprocessing python-multithreading

所以我想运行一个函数,它可以在网络上搜索信息,也可以直接从我自己的 mysql 数据库中搜索信息。 第一个过程会比较耗时,第二个过程相对较快。

考虑到这一点,我创建了一个启动复合搜索(find_compound_view)的进程。如果该过程完成得相对较快,则意味着它存在于数据库中,因此我可以立即呈现结果。否则,我将渲染“drax_retrieve_data.html”。

我想出的愚蠢解决方案是运行该函数两次,一次是为了检查该过程是否需要很长时间,另一次是为了实际获取该函数的返回值。这很大程度上是因为我不知道如何返回 find_compound_view 函数的值。我尝试过谷歌搜索,但似乎找不到如何专门从 Process 类返回值。

   p = Process(target=find_compound_view, args=(form,))
        p.start()
        is_running = p.is_alive()
        start_time=time.time()
        while is_running:
            time.sleep(0.05)
            is_running = p.is_alive()
            if time.time() - start_time > 10 :
                print('Timer exceeded, DRAX is retrieving info!',time.time() - start_time)
                return render(request,'drax_internal_dbs/drax_retrieving_data.html')
        compound = find_compound_view(form,use_email=False)

   if compound:
      data=*****
      return  render(request, 'drax_internal_dbs/result.html',data)

最佳答案

您将需要一个 multiprocessing.Pipemultiprocessing.Queue 将结果发送回您的父进程。如果你只做I/0,你应该使用Thread而不是Process,因为它更轻量级并且大部分时间都花在等待上。我将向您展示一般情况下进程和线程是如何完成的。

<小时/>

使用队列进行处理

多处理队列构建在管道之上,并且访问与锁/信号量同步。队列是线程和进程安全的,这意味着您可以将一个队列用于多个生产者/消费者进程,甚至这些进程中的多个线程。添加队列中的第一项也会在调用进程中启动一个供给线程。 multiprocessing.Queue 的额外开销使得在单生产者/单消费者场景中使用管道更可取且性能更高。

以下是如何使用 multiprocessing.Queue 发送和检索结果:

from multiprocessing import Process, Queue

SENTINEL = 'SENTINEL'

def sim_busy(out_queue, x):
    for _ in range(int(x)):
        assert 1 == 1
    result = x
    out_queue.put(result)
    # If all results are enqueued, send a sentinel-value to let the parent know
    # no more results will come.
    out_queue.put(SENTINEL)


if __name__ == '__main__':

    out_queue = Queue()

    p = Process(target=sim_busy, args=(out_queue, 150e6))  # 150e6 == 150000000.0
    p.start()

    for result in iter(out_queue.get, SENTINEL):  # sentinel breaks the loop
        print(result)

队列作为参数传递到函数中,结果是队列上的 .put() 和队列中的父 get.().get() 是一个阻塞调用,直到获取某些内容(可以指定超时参数)后才会恢复执行。请注意,sim_busy 在这里所做的工作是 CPU 密集型的,此时您会选择进程而不是线程。

<小时/>

工艺与管道

对于一对一连接,管道就足够了。设置几乎相同,只是方法的命名不同,并且对 Pipe() 的调用返回两个连接对象。在双工模式下,两个对象都是读写端,duplex=False(单工)第一个连接对象是管道的读端,第二个是写端。在这个基本场景中,我们只需要一个单工管道:

from multiprocessing import Process, Pipe

SENTINEL = 'SENTINEL'


def sim_busy(write_conn, x):
    for _ in range(int(x)):
        assert 1 == 1
    result = x
    write_conn.send(result)
    # If all results are send, send a sentinel-value to let the parent know
    # no more results will come.
    write_conn.send(SENTINEL)


if __name__ == '__main__':

    # duplex=False because we just need one-way communication in this case.
    read_conn, write_conn = Pipe(duplex=False)

    p = Process(target=sim_busy, args=(write_conn, 150e6))  # 150e6 == 150000000.0
    p.start()

    for result in iter(read_conn.recv, SENTINEL):  # sentinel breaks the loop
        print(result)
<小时/>

线程和队列

为了与线程一起使用,您需要切换到queue.Queuequeue.Queue 构建在 collections.deque 之上,添加了一些锁以使其线程安全。与多处理的队列和管道不同,放在 queue.Queue 上的对象不会被 pickle。由于线程共享相同的内存地址空间,因此不需要进行内存复制的序列化,只传输指针。

from threading import Thread
from queue import Queue
import time

SENTINEL = 'SENTINEL'


def sim_io(out_queue, query):
    time.sleep(1)
    result = query + '_result'
    out_queue.put(result)
    # If all results are enqueued, send a sentinel-value to let the parent know
    # no more results will come.
    out_queue.put(SENTINEL)


if __name__ == '__main__':

    out_queue = Queue()

    p = Thread(target=sim_io, args=(out_queue, 'my_query'))
    p.start()

    for result in iter(out_queue.get, SENTINEL):  # sentinel-value breaks the loop
        print(result)
<小时/>
  • 阅读 here为什么结果在iter(out_queue.get, SENTINEL)中: 如果可能的话,应该优先于 while True...break 设置。
  • 阅读 here为什么您应该在所有脚本中,特别是在多处理中使用 if __name__ == '__main__':
  • 有关 get() 用法的更多信息 here .

关于python - 如何从进程或线程实例返回值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53413326/

相关文章:

python - 流媒体上传请求?

python - 使用 python-gnupg 解密用 gpg 加密的文件

java - 为什么 toMap 的错误放置会导致 RXJava 出现问题?

java - 解锁锁定同步块(synchronized block)的可靠方法

multithreading - Sitecore 预定作业的优先级

Python 多处理性能

python - Python 中是否可以在线程内生成进程?

python - 为什么我在使用 googletrans 时会收到 ModuleNotFoundError

python - Kmeans 聚类在 tensorflow 中如何工作?

python - 是否可以在带有 Windows 的模块中使用多处理?