所以我想运行一个可以在网络上搜索信息或直接从我自己的mysql数据库中搜索信息的功能。 第一个过程很耗时,第二个过程相对较快。
考虑到这一点,我创建了一个启动此复合搜索的过程(find_compound_view)。如果该过程完成得相对较快,则表示该过程已存在于数据库中,因此我可以立即呈现结果。否则,我将渲染“ drax_retrieving_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)
答案 0 :(得分:1)
您将需要multiprocessing.Pipe
或multiprocessing.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.Queue
。 queue.Queue
构建在collections.deque
之上,并添加了一些锁以使其成为线程安全的。与多处理的队列和管道不同,放置在queue.Queue
上的对象不会被腌制。由于线程共享相同的内存地址空间,因此不需要进行用于内存复制的序列化,因此仅传输指针。
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)