問題描述
所以我想運行一個函數,它既可以在網上搜索信息,也可以直接從我自己的 mysql 數據庫中搜索信息.第一個過程會很耗時,第二個相對較快.
So I want to run a function which can either search for information on the web or directly from my own mysql database. The first process will be time-consuming, the second relatively fast.
考慮到這一點,我創建了一個啟動此復合搜索 (find_compound_view) 的進程.如果該過程相對較快地完成,則意味著它存在于數據庫中,因此我可以立即呈現結果.否則,我將渲染drax_retrieving_data.html".
With this in mind I create a process which starts this compound search (find_compound_view). If the process finishes relatively fast it means it's present on the database so I can render the results immediately. Otherwise, I will render "drax_retrieving_data.html".
我想出的愚蠢解決方案是運行該函數兩次,一次是檢查該過程是否需要很長時間,另一次是實際獲取函數的返回值.這很大程度上是因為我不知道如何返回我的 find_compound_view 函數的值.我試過谷歌搜索,但似乎找不到如何從 Process 類中返回值.
The stupid solution I came up with was to run the function twice, once to check if the process takes a long time, the other to actually get the return values of the function. This is pretty much because I don't know how to return the values of my find_compound_view function. I've tried googling but I can't seem to find how to return the values from the class Process specifically.
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.Pipe
或一個 multiprocessing.Queue
將結果發送回您的父進程.如果你只是做 I/0,你應該使用 Thread
而不是 Process
,因為它更輕量級并且大部分時間都花在等待上.我正在向您展示它是如何為進程和線程完成的.
You will need a multiprocessing.Pipe
or a multiprocessing.Queue
to send the results back to your parent-process. If you just do I/0, you should use a Thread
instead of a Process
, since it's more lightweight and most time will be spend on waiting. I'm showing you how it's done for Process and Threads in general.
使用隊列處理
多處理隊列建立在管道之上,訪問與鎖/信號量同步.隊列是線程和進程安全的,這意味著您可以將一個隊列用于多個生產者/消費者進程,甚至這些進程中的多個線程.在隊列中添加第一項也將在調用過程中啟動一個饋線線程.multiprocessing.Queue
的額外開銷使得在單生產者/單消費者場景中使用管道更可取且性能更高.
The multiprocessing queue is build on top of a pipe and access is synchronized with locks/semaphores. Queues are thread- and process-safe, meaning you can use one queue for multiple producer/consumer-processes and even multiple threads in these processes. Adding the first item on the queue will also start a feeder-thread in the calling process. The additional overhead of a multiprocessing.Queue
makes using a pipe for single-producer/single-consumer scenarios preferable and more performant.
以下是使用 multiprocessing.Queue
發送和檢索結果的方法:
Here's how to send and retrieve a result with a 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 密集型的,此時您會選擇進程而不是線程.
The queue is passed as argument into the function, results are .put()
on the queue and the parent get.()
s from the queue. .get()
is a blocking call, execution does not resume until something is to get (specifying timeout parameter is possible). Note the work sim_busy
does here is cpu-intensive, that's when you would choose processes over threads.
流程與管道
對于一對一的連接,管道就足夠了.設置幾乎相同,只是方法名稱不同,對 Pipe()
的調用返回兩個連接對象.在雙工模式下,兩個對象都是讀寫端,duplex=False
(單工)第一個連接對象是管道的讀端,第二個是寫端.在這個基本場景中,我們只需要一個單工管道:
For one-to-one connections a pipe is enough. The setup is nearly identical, just the methods are named differently and a call to Pipe()
returns two connection objects. In duplex mode, both objects are read-write ends, with duplex=False
(simplex) the first connection object is the read-end of the pipe, the second is the write-end. In this basic scenario we just need a simplex-pipe:
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
上的對象不會被腌制.由于線程共享相同的內存地址空間,內存復制的序列化是不必要的,只傳輸指針.
For use with threading, you want to switch to queue.Queue
. queue.Queue
is build on top of a collections.deque
, adding some locks to make it thread-safe. Unlike with multiprocessing's queue and pipe, objects put on a queue.Queue
won't get pickled. Since threads share the same memory address-space, serialization for memory-copying is unnecessary, only pointers are transmitted.
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)
<小時>
- 閱讀這里為什么
for result in iter(out_queue.get, SENTINEL):
在可能的情況下,應該優先于while True...break
設置. - 閱讀這里為什么你應該使用
if __name__ == '__main__':
您的腳本,尤其是在多處理中. - 更多關于
get()
-用法的信息這里. - Read here why
for result in iter(out_queue.get, SENTINEL):
should be prefered over awhile True...break
setup, where possible. - Read here why you should use
if __name__ == '__main__':
in all your scripts and especially in multiprocessing. - More about
get()
-usage here.
這篇關于如何從 Process- 或 Thread 實例返回值?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!