原來可以這麼寫(10):同步與非同步

來到第十篇原來這麼寫啦,看來這個系列真的常駐我這個部落格真的很久呢!

要冷靜啊!

然後這次真的是史上我接過任務最難的一波,有一天還差點情緒崩潰在工作現場爆哭… 真的覺得自己很丟臉很誇張……

不過事後想想,那是因為我自己對自己的要求也實在太高了,也一直過度自責、苛責自己的規劃上有很大的問題….. 真的很辛苦各位我的同事。總之,這次的經驗告訴我:要努力試著讓情緒歸情緒、工作歸工作哭完,問題還是在那裡,我們一定要努力地解決問題。工程師的存在正是為此啊。

我自己最喜歡得形容詞就是忠心!忠心於工作、忠心於自己的技術能力、也忠心於自己的信仰。我想藉著上面的事件也再度應證與難怪自己為什麼會有那種過度反應了吧

結論是:calm down ! 挽起袖子來解決問題

小說的匯入任務

這個任務為什麼對我來說蠻困難的,我覺得技術問題是一回事,其次我自己也檢討是不是太晚將問題丟出來了?我的個性常常是獨立做事,說真的還蠻就事論事得、原生工程師性格。而我通常認為我自己不是那個第一個遇到同樣問題的人,所以總是自己想辦法處理、想辦法解決…. 像是Laravel 的開發與專案、API維護上,我其實就非常游刃有餘、自由自在。(當然溝通上面的gap 與問題是需要慢慢的與團隊磨合與自己努力調整的),DevOps 的精神就是逐步改善麻!

但我卻忽略有時候其實是有時間上的問題,在過年前要匯入這麼多的小說,一共12000多章節,剛好我台東人在過年期間卻要請長長的年假,我才驚訝發現:我hold 不住了。看來,下次也要注意時間,好讓PM與SA 能夠發覺與注意到我的狀況,能hold 住專案

自動匯入方案的產生

不過還好啦,謝謝同事、夥伴們的體諒與幫助。在禮拜五怒給他加班到十一點的時候把這個自動化方案寫出來(但當然啦,這個我覺得也需要事先給PM測試,所以同時我也預備自己的手動匯入程式方案…但等等分享我遇到的問題與啟發)

手動匯入的些許失敗經驗與啟發

但說真的,小說匯入其實這次第二波了。上一次真的我自己沒有準備好… 可是這次我吸取第一次的失敗經驗,重新調整流程、設計。於是這次在匯入資料上面就非常的順利,還記得第一次營運單位有兩天的時間都無法到後台修改資料…但這次一個下午就搞定了。

事實上,我只是把匯入分成兩個階段進行,第一階段是把資料放進去資料庫(就是這個步驟才會不建議營運單位修改資料,以免我們的id 亂跳…),而第二階段是去別人小說的網站把音擋下載下來上傳到我們server上的指定位置,驅動我們同事寫好的自建音檔模組。於是完成了這整個匯入流程。

而第二階段的處理原本我用python 寫 request.get(url) 這樣去下載,寫檔案後上傳的“同步方案”,一支處理就要10秒多…. 然後12000多就… 超級慢的啦!

中間還遇到工作電腦爆掉的問題… 真的是很衰… 第一次遇到…. 但所幸謝謝我們家的MIS幫我工作電腦換好一個power 這樣,於是只有一點點時間是不知道怎麼辦而已。

隔天早上,發現我那支居然跑到一半不跑了… 還好我之前在設計上有納入可中斷性,就算中斷了重新執行也可以從還沒處理的部分繼續接著處理… 但就像剛剛說的一個一個上傳真的很慢啊…. 於是開始研究 python 的 非同步方案版本…

import aiohttp
import aiofiles
import asyncio
import time
import os


#定義協程(coroutine)
async def main(links):

    async with aiohttp.ClientSession() as session:
        tasks = [
            asyncio.create_task(fetch(data['url'], data['episodeId'], session)) for data in links
        ]  # 建立任務清單
        await asyncio.gather(*tasks)  # 打包任務清單及執行


#定義協程(coroutine)
async def fetch(link, id, session):
    async with session.get(link) as response:  #非同步發送請求
        if response.status == 200:
            f = await aiofiles.open('/tmp/file.mp3', mode='wb')
            await f.write(await resp.read())
            await f.close()
        try:
            # s3 upload
            print("{} upload success")
        except Exception as e:
            print("{} upload error")

        os.remove('tmp/file.mp3')



start_time = time.time()  #開始執行時間
loop = asyncio.get_event_loop()  #建立事件迴圈(Event Loop)

#  episodes = ...

loop.run_until_complete(main(episodes))  #執行協程(coroutine)
print("花費:" + str(time.time() - start_time) + "秒")

於是,我在家中研究寫了這樣一個模擬出來的程式碼… 然後執行下卻發現… 靠 檔案因為非同步的關係所以就產生Permission error 的錯誤,在修正後變成以下這個版本…(但不是全部程式碼,僅是示意)

import aiohttp
import aiofiles
import asyncio
import time
import os


#定義協程(coroutine)
async def main(links):

    async with aiohttp.ClientSession() as session:
        tasks = [
            asyncio.create_task(fetch(data['url'], data['episodeId'], session)) for data in links
        ]  # 建立任務清單
        await asyncio.gather(*tasks)  # 打包任務清單及執行


#定義協程(coroutine)
async def fetch(link, id, session):
    await asyncio.sleep(10+int(random.random()*10))
    try:
        async with session.get(link) as response:
            if response.status == 200:
                FileHelper.upload_s3_audio_files(id, await response.read())
                print("{} upload success".format(id))
            else:
                print('status not 200')
                print("{} upload error".format(id))
    except Exception as e:
        print(e)
        print("{} upload error".format(id))



start_time = time.time()  #開始執行時間
loop = asyncio.get_event_loop()  #建立事件迴圈(Event Loop)

#  episodes = ...
loop.run_until_complete(main(episodes))  #執行協程(coroutine)

print("花費:" + str(time.time() - start_time) + "秒")

但還是無法解決所有的問題,有時還是會噴一堆錯誤,或者是Response payload is not completed , 因此… 還在想一想怎麼樣可以更好…

但比較好的是:因為這是第一次匯入,當然資料爆多。之後的更新就不會有那麼多了… 而確實使用非同步的寫法與方案在第二階段處理上快了很多…

此事件帶來我的啟發是:這麼大量的上傳下載處理還是要搞非同步啊

小君曰:看來,我需要好好理解非同步程式設計啊....

原來可以這麼寫(1):新工作第一週

去年的12月,我從上一間公司離職。其實,一月是打算好好去玩~

突然覺得自己韓國去得真是很好的時候,不然可能回來就要自行隔離幾天了XD

想知道韓國旅遊心得的可以到我的樂在信仰中喔:https://r567tw.tw/2020韓國之旅/

然後二月就是各種找工作、思考要做那些工作…..然後各種的無聲卡、拒絕、邀請進去…。

有一家做博弈的接案公司最誇張,其實我本來就沒打算做博弈了,去面試也只是想說「以戰養戰」的態度、寫寫題目,看看有沒有需要再精進的…(是說這間在話術上也很厲害,在頁面其實沒有看到博弈,他們也說他們不標榜自己是博弈,只是接案剛好有大部分都是接博弈的……),然後我就隨意地寫寫,甚至幾題我是空白沒寫,想說記起來回家研究怎麼寫會更好…結果超好笑的是下禮拜居然還發給我錄取通知….(到底有多缺人Xd)

還有一間是說我們「氣不合」,這個理由真的很靠杯,雖然我也知道面試這種事其實與技術能力沒有太大關聯,技術能力只是代表你能帶多少籌碼,最重要的還是面試官喜不喜歡你麻~ 但直接用「談論起來氣不合」這種直白的理由真的會覺得很不尊重面試者,這間公司的名稱就不公佈了,想知道可以私訊~

總之三月之後正式工作,進入了一間大型傳統機構,薪水上蠻滿意的。不過我想先等三個月培訓期度過了在公開自己在哪裡好了,不然培訓期沒過真的會很好笑很尷尬XD

不過我覺得是時候應該要好好記錄工作上的筆記與東西了,畢竟有紀錄有籌碼,這樣下次在跳、再找也更有話可以嘴,同時也是一種回顧自己進步的軌跡的概念~

有一句話我很喜歡:「Don’t Prove; Improve」連結

話不多說,這個系列的文章就叫做「原來可以這麼寫」,紀錄我看前輩、同事的code的筆記、以及一些工作上學到的新概念、新技術~然後後面的標題可以自行發揮創意,像這週就比較沒創意:新工作第一週!

(1) 原來可以直接創造一個class…

trait TraitA {
     public    function   HelloWorld(){
           echo'Hello World';
      }
}
trait TraitB {
   public   function   HELLOTWO(){
       echo'hELLO tWO ';
    }
}
$helper = new class {
      useTraitA,TraitB;
};;
$helper->HelloWorld();

 

(2) ‘<=>’ 運算子

這個很少遇到,沒寫道真的不會記得~

他會比較兩邊的值,然後會回傳0,1,-1

至於規則可以參考:https://www.php.net/manual/zh/language.operators.comparison.php

 

(3) filter_var

https://blog.xuite.net/coke750101/networkprogramming/57002113-PHP+filter_var%28%29+%E5%87%BD%E6%95%B8Filter+%E5%87%BD%E6%95%B8

 

(4) AWS

1. ECR: 類似aws方提供的docker hub
2. KMS: 加解密服務
3. Lambda : 微服務的部分
(5) 匿名函數
“`
$gifts->sort(fn($a, $b) => $b->created_at <=> $a->created_at)->values()
// 越後面的日子就會排越前面~
“`
小君曰:這能這個系列應該會是週更,但有可能會是月更,阿不管啦,我想寫就寫啦XD