So I have been searching far an wide for this. I want to run three functions in parallel, when one finishes return this value, stop the two others.
I have tried with asynciop, multiprocess and concurrent.futures, and I still can not get it to work.
As an example I have a function that returns 0 when above a certain threshold, and some number otherwise. To test my implementation I want to return the last non-zero value.
My problem is that regardless of whatever I try, all three methods complete every time. Instead of breaking when a match has been found.
from concurrent.futures import FIRST_COMPLETED, ThreadPoolExecutor, wait
def first_zero(f, values=[10, 10**2, 10**3]):
for i in values:
if f(i) == 0:
return i
return values[-1]
def bisect_search(f, first, last):
if f(first) == 0:
return first
middle = (last + first) // 2
while True:
# print(middle, "bisect")
if abs(last - first) <= 1:
return first
middle = (last + first) // 2
if f(middle) > 0:
first = middle
else:
last = middle
def linear_search(f, start, stop, increment):
i = start
minimum = min(start, stop)
maximum = max(start, stop)
if increment < 0:
while minimum <= i <= maximum:
if f(i) != 0:
return i
i += increment
else:
while minimum <= i <= maximum:
if f(i) == 0:
return i - increment
i += increment
return i
def linear_binary_search(f, start=0):
stop = first_zero(f)
tasks = [
(linear_search, [f, start, stop, 1]),
(linear_search, [f, stop, start, -1]),
(bisect_search, [f, start, stop]),
]
executor = ThreadPoolExecutor(max_workers=len(tasks))
futures = [executor.submit(task, *args) for (task, args) in tasks]
done, _ = wait(futures, return_when=FIRST_COMPLETED)
executor.shutdown(wait=False, cancel_futures=True)
return done.pop().result()
if __name__ == "__main__":
import random
import time
target = 995
def f(x):
time.sleep(0.01)
if x <= target:
return random.randint(1, 1000)
return 0
# Comment the following line to see
# how much slower the concurrent version is
print(linear_binary_search(f))
stop = first_zero(f)
print(linear_search(f, stop, 0, -1))