需求:在調用阿里雲 函數式計算 時,由於 其函數式計算系統 在分配系統資源時,可能存在 多個任務分配給同一個 服務器(每個服務器2核3G內存),導致 多個相同任務在多線程調用函數式計算時 總有幾個 因爲資源分配不均返回較慢(包括帶寬問題);並且 在多線程 調用函數式計算時,每個線程的函數相同,並且根據業務需求,只要把返回結果list 拼接一下並且滿足指定長度即可;
解決方法:使用多線程的 先返回的任務先處理的方法,比如 多線程請求20個函數式計算任務,但是只需要先返回的10個任務即可,剩下的10個任務 忽略;這樣能保證 最大程度最大概率的 前10個任務返回總體時間很短,從而 優化接口執行時間;
圖示:
技術名: python+ThreadPoolExecutor+as_completed
主要技術點:as_completed
實例代碼:
from concurrent.futures import ThreadPoolExecutor, as_completed
import time
def get_ali_fun(times):
time.sleep(times)
return times
executor = ThreadPoolExecutor()
urls = [3, 2, 4]
all_task = [executor.submit(get_ali_fun, url) for url in urls]
result_list = []
for future in as_completed(all_task):
data = future.result()
result_list.append(data)
print("獲取數據,耗時 {}s".format(data))
if len(result_list) == 2:
print("先返回的數據已經滿足條件 則 剩下的1個線程結果 不再處理。。。")
break
print("繼續處理下面程序")
as_completed()
方法是一個生成器,在沒有任務完成的時候,會阻塞,在有某個任務完成的時候,會yield
這個任務,就能執行for循環下面的語句,然後繼續阻塞住,循環到所有的任務結束。從結果也可以看出,先完成的任務會先通知主線程。
關於阿里雲函數式計算相關 知識備註:
1.在調用其服務時,如果需要分析 耗時,需要 考慮 服務內部函數執行時間 和 來回網絡帶寬時間;
2.截止2020.3.15 問的其技術人員 其 函數計算 在不調用15分鐘後 釋放資源(以後可能會縮短),如果對時間敏感,可以通過airflow等 使用定時任務方式調用函數計算,不讓其釋放資源(冷啓動至少10s耗費);不要使用 阿里雲內置的 預留資源(太貴了。。。)
3.函數式計算系統 在分配資源時 是根據內存進行分配,每個服務器2核3G內存,如果函數 分配內存1G,則有一定 概率 3個函數都在一個服務器上,這樣 如果對於併發時間敏感的任務,則有一定的概率 耗時增加;最極端優化方式:一個函數分配3G內存,則保證一個任務1個服務器;缺點是 太費錢。。。
4.如果對時間敏感,需要 考慮 增加帶寬(減少帶寬導致時間過長的概率,然而時間操作 仍有很大概率),或者 配置 雲服務器 和 函數式計算同一個VPC(讓其在同一個內網中)
5.如果一個藉口 調用多個 函數 進行函數式計算,如果沒有 函數間的 依賴,可以考慮 進程+協程 等讓其同時 運行 從而節約時間
6.函數式計算的 時間優化 計算優化到盡頭 如果 還是需要考慮 資金問題,那仍有 很大概率 無法達到100% 預期時間;因爲 函數式計算系統的 資源分配 是隨機的,可能 相同函數的 多個任務 都在一個服務器上,這樣就比 在不同服務器上 耗時增加;所以 隨緣吧。。。
as_completed參數 過期時間 設置,注意 如果不添加過期時間,並且函數如果沒有返回值,則此線程一直存在,可能造成內存逐漸增加的情況
# -*- coding: utf-8 -*-
"""
(C) Guangcai Ren <[email protected]>
All rights reserved
create time '2020/3/30 18:59'
Module usage:
"""
from concurrent.futures._base import as_completed, TimeoutError
from concurrent.futures.thread import ThreadPoolExecutor
def sleep_fun(_time):
"""
耗時操作
:param _time:
:return:
"""
import time
time.sleep(_time)
return _time
pool = ThreadPoolExecutor()
pool_result = [pool.submit(sleep_fun, func_param) for func_param in [1, 1000]]
try:
# as_completed添加超時時間,如果不添加,則此 線程池一直存在;
for result in as_completed(pool_result, 2):
print(result.result())
print('do other thing!')
except TimeoutError as e:
# 清除相關資源,參數 默認爲False,需要 所有線程都返回數據才清空資源;參數爲 True,則直接清空資源
pool.shutdown(True)
print('shut down!')
相關鏈接:
https://www.jianshu.com/p/b9b3d66aa0be