詳細:我正在使用 python 制作一個小應用程式,它可以抓取前 100 首歌曲串列并從中創建一個 Spotify 播放串列。我的瓶頸是 spotify API 一次只允許您搜索一首歌曲(以獲取其內部 spotify ID)。
簡而言之:我嘗試了多執行緒,但結果好壞參半。
作為參考,這是搜索歌曲所做的,并不完全相關:
def __search_song(self, song: str):
result = self.sp.search(song " NOT Karaoke", limit=1, type="track")
try:
sid = result["tracks"]["items"][0]["uri"]
except IndexError:
pass
else:
self.song_list.append(sid)
初步實施:
def __populate_playlist(self, song_list: list, pid: str):
for song in song_list:
self.__search_song(song)
self.sp.playlist_add_items(pid, self.song_list)
這是正常的執行,“一個接一個”,它作業得很好,但是速度很慢,并且由于 UI 導致視窗掛起(Tkinter 需要不斷重繪 )。
使用執行緒和佇列的多執行緒:
q = queue.Queue()
def __worker():
while True:
item = q.get()
q.task_done()
threading.Thread(target=__worker, daemon=True).start()
def __populate_playlist(self, song_list: list, pid: str):
for song in song_list:
q.put(self.__search_song(song))
q.join()
self.sp.playlist_add_items(pid, self.song_list)
這有效,但是,它比原來的速度略快。它確實解決了程式似乎沒有回應的問題,但速度不夠快。
然后我嘗試洗掉佇列并實作無序執行緒。
def __populate_playlist(self, song_list: list, pid: str):
# multiprocessing support
threads = []
for song in song_list:
t = threading.Thread(target=self.__search_song, args=(song, ))
threads.append(t)
for thread in threads:
thread.start()
for thread in threads:
thread.join()
self.sp.playlist_add_items(pid, self.song_list)
這非常快,我說的是從 23 秒減少到 8 秒。顯然,這會帶來意想不到的后果,即播放串列被洗牌,不再是真正的前 100 名。
我的問題很簡單,我的佇列實作是否存在問題,或者使用佇列系統是否固有地提供了這么多開銷?這是我第一次在應用程式中實作多執行緒,所以我可能會遺漏一些東西。
為了再次迭代用例,我并不關心哪個先完成,只要保持順序即可。我考慮過存盤串列的初始順序并使用字典來保存其順序和識別 ID,但我仍在考慮它的實際實作。
uj5u.com熱心網友回復:
如前所述,如果您想要異步呼叫,則很難保證訂單。但是將 ID 映射到歌曲名稱的簡單實作是:
def __search_song(self, song: str):
result = self.sp.search(song " NOT Karaoke", limit=1, type="track")
try:
sid = result["tracks"]["items"][0]["uri"]
except IndexError:
pass
else:
self.song_list.append(sid)
self.song_to_sid[song] = sid
鑒于 dictsong_to_sid在您的班級中已實體化。如果您然后只是迭代您的第一個地圖(如果這是按順序),您可以附加映射的 sid 以獲得有序的播放串列。
運行該__populate_playlist功能后,您可以執行以下操作:
top_hundred_playlist = []
for song_id in self.song_list:
top_hundred_playlist(self.song_to_sid[song_id])
uj5u.com熱心網友回復:
在 Albin Sid?s 的幫助下,最終代碼看起來像這樣:
def __search_song(self, song: str):
"""searches a song by a string song name returns spotify URI id"""
result = self.sp.search(song " NOT Karaoke", limit=1, type="track")
try:
sid = result["tracks"]["items"][0]["uri"]
except IndexError:
self.song_to_sid[song] = ""
else:
self.song_to_sid[song] = sid
def __populate_playlist(self, song_list: list, pid: str):
# multiprocessing support
top_hundred_ids = []
threads = []
for song in song_list:
self.song_list_names.append(song)
t = threading.Thread(target=self.__search_song, args=(song, ))
threads.append(t)
for thread in threads:
thread.start()
for thread in threads:
thread.join()
for song_id in self.song_list_names:
song_value = self.song_to_sid[song_id]
if song_value != "":
top_hundred_ids.append(song_value)
self.sp.playlist_add_items(pid, top_hundred_ids)
它最終比完全異步的解決方案慢了一秒鐘,所以我認為這是成功的方法。我仍然愿意對佇列系統的開銷進行任何澄清,但總而言之,這很棒。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/448879.html
下一篇:API鏈接中的,是什么意思?
