亚洲一区精品自拍_2021年国内精品久久_男同十八禁gv在线观看_免费观看a级性爱黄片

Article / 文章中心

教你怎么用手機(jī)寫(xiě)代碼:基于 Serverless 的在線編程能力實(shí)驗(yàn)

發(fā)布時(shí)間:2021-12-09 點(diǎn)擊數(shù):839

隨著計(jì)算機(jī)科學(xué)與技術(shù)的發(fā)展,越來(lái)越多的人開(kāi)始接觸編程,也有越來(lái)越多的在線編程平臺(tái)誕生。以 Python 語(yǔ)言的在線編程平臺(tái)為例,大致可以分為兩類:


  • 一類是 OJ 類型的,即在線評(píng)測(cè)的編程平臺(tái),這類的平臺(tái)特點(diǎn)是阻塞類型的執(zhí)行,即用戶需要一次性將代碼和標(biāo)準(zhǔn)輸入內(nèi)容提交,當(dāng)程序執(zhí)行完成會(huì)一次性將結(jié)果返回;
  • 另一類則是學(xué)習(xí)、工具類的在線編程平臺(tái),例如 Anycodes 在線編程等網(wǎng)站,這一類平臺(tái)的特點(diǎn)是非阻塞類型的執(zhí)行,即用戶可以實(shí)時(shí)看到代碼執(zhí)行的結(jié)果,以及可以實(shí)時(shí)內(nèi)容進(jìn)行內(nèi)容的輸入。


但是,無(wú)論是那種類型的在線編程平臺(tái),其背后的核心模塊( “代碼執(zhí)行器”或“判題機(jī)”)都是極具有研究?jī)r(jià)值,一方面,這類網(wǎng)站通常情況下都需要比要嚴(yán)格的“安全機(jī)制”,例如程序會(huì)不會(huì)有惡意代碼,出現(xiàn)死循環(huán)、破壞計(jì)算機(jī)系統(tǒng)等,程序是否需要隔離運(yùn)行,運(yùn)行時(shí)是否會(huì)獲取到其他人提交的代碼等;


另一方面,這類平臺(tái)通常情況下都會(huì)對(duì)資源消耗比較大,尤其是比賽來(lái)臨時(shí),更是需要突然間對(duì)相關(guān)機(jī)器進(jìn)行擴(kuò)容,必要時(shí)需要大規(guī)模集群來(lái)進(jìn)行應(yīng)對(duì)。同時(shí)這類網(wǎng)站通常情況下也都有一個(gè)比較大的特點(diǎn),那就是觸發(fā)式,即每個(gè)代碼執(zhí)行前后實(shí)際上并沒(méi)有非常緊密的前后文關(guān)系等。


隨著 Serverless 架構(gòu)的不斷發(fā)展,很多人發(fā)現(xiàn) Serverless 架構(gòu)的請(qǐng)求級(jí)隔離和極致彈性等特性可以解決傳統(tǒng)在線編程平臺(tái)所遇到的安全問(wèn)題和資源消耗問(wèn)題,Serverless 架構(gòu)的按量付費(fèi)模式,可以在保證在線編程功能性能的前提下,進(jìn)一步降低成本。所以,通過(guò) Serverless 架構(gòu)實(shí)現(xiàn)在線編程功能的開(kāi)發(fā)就逐漸的被更多人所關(guān)注和研究。本文將會(huì)以阿里云函數(shù)計(jì)算為例,通過(guò) Serverless 架構(gòu)實(shí)現(xiàn)一個(gè) Python 語(yǔ)言的在線編程功能,并對(duì)該功能進(jìn)一步的優(yōu)化,使其更加貼近本地本地代碼執(zhí)行體驗(yàn)。


在線編程功能開(kāi)發(fā)


一個(gè)比較簡(jiǎn)單的、典型的在線編程功能,在線執(zhí)行模塊通常情況下是需要以下幾個(gè)能力:


  • 在線執(zhí)行代碼
  • 用戶可以輸入內(nèi)容
  • 可以返回結(jié)果(標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)錯(cuò)誤等)

除了在線編程所需要實(shí)現(xiàn)的功能之外,在線編程在 Serverless 架構(gòu)下,所需要實(shí)現(xiàn)的業(yè)務(wù)邏輯,也僅僅被收斂到關(guān)注代碼執(zhí)行模塊即可:獲取客戶端發(fā)送的程序信息(包括代碼、標(biāo)準(zhǔn)輸入等),將代碼緩存到本地,執(zhí)行代碼,獲取結(jié)果,但會(huì)給客戶端,整個(gè)架構(gòu)的流程簡(jiǎn)圖為:


image


關(guān)于執(zhí)行代碼部分,可以通過(guò) Python 語(yǔ)言的 subprocess 依賴中的 Popen() 方法實(shí)現(xiàn),在使用 Popen() 方法時(shí),有幾個(gè)比較重要的概念,需要明確:


  • subprocess.PIPE:一個(gè)可以被用于 Popen 的stdin 、stdout 和 stderr 3 個(gè)參數(shù)的特殊值,表示需要?jiǎng)?chuàng)建一個(gè)新的管道;
  • subprocess.STDOUT:一個(gè)可以被用于 Popen 的 stderr 參數(shù)的輸出值,表示子程序的標(biāo)準(zhǔn)錯(cuò)誤匯合到標(biāo)準(zhǔn)輸出;

所以,當(dāng)我們想要實(shí)現(xiàn)可以:

進(jìn)行標(biāo)準(zhǔn)輸入(stdin),獲取標(biāo)準(zhǔn)輸出(stdout)以及標(biāo)準(zhǔn)錯(cuò)誤(stderr)的功能

可以簡(jiǎn)化代碼實(shí)現(xiàn)為:

image


除代碼執(zhí)行部分之外,在 Serverless 架構(gòu)下,獲取到用戶代碼并將其存儲(chǔ)過(guò)程中,需要額外注意函數(shù)實(shí)例中目錄的讀寫(xiě)權(quán)限。通常情況下,在函數(shù)計(jì)算中,如果不進(jìn)行硬盤(pán)掛載,只有/tmp/目錄是有可寫(xiě)入權(quán)限的。所以在該項(xiàng)目中,我們將用戶傳遞到服務(wù)端的代碼進(jìn)行臨時(shí)存儲(chǔ)時(shí),需要將其寫(xiě)入臨時(shí)目錄/tmp/,在臨時(shí)存儲(chǔ)代碼的時(shí)候,還需要額外考慮實(shí)例復(fù)用的情況,所以此時(shí),可以為臨時(shí)代碼提供臨時(shí)的文件名,例如:

# -*- coding: utf-8 -*-

import randomrandom

Str = lambda num=5: "".join(random.sample('abcdefghijklmnopqrstuvwxyz', num))

path = "/tmp/%s"% randomStr(5)

完整的代碼實(shí)現(xiàn)為:


# -*- coding: utf-8 -*-

import json

import uuid

import random

import subprocess

# 隨機(jī)字符串

randomStr = lambda num=5: "".join(random.sample('abcdefghijklmnopqrstuvwxyz', num))

# Response

class Response:

   def __init__(self, start_response, response, errorCode=None):

       self.start = start_response

       responseBody = {

           'Error': {"Code": errorCode, "Message": response},

       } if errorCode else {

           'Response': response

       }

       # 默認(rèn)增加uuid,便于后期定位

       responseBody['ResponseId'] = str(uuid.uuid1())

       self.response = json.dumps(responseBody)


   def __iter__(self):

       status = '200'

       response_headers = [('Content-type', 'application/json; charset=UTF-8')]

       self.start(status, response_headers)

       yield self.response.encode("utf-8")


def WriteCode(code, fileName):

   try:

       with open(fileName, "w") as f:

           f.write(code)

       return True

   except Exception as e:

       print(e)

       return False


def RunCode(fileName, input_data=""):

   child = subprocess.Popen("python %s" % (fileName),

                            stdin=subprocess.PIPE,

                            stdout=subprocess.PIPE,

                            stderr=subprocess.STDOUT,

                            shell=True)

   output = child.communicate(input=input_data.encode("utf-8"))

   return output[0].decode("utf-8")


def handler(environ, start_response):

   try:

       request_body_size = int(environ.get('CONTENT_LENGTH', 0))

   except (ValueError):

       request_body_size = 0

   requestBody = json.loads(environ['wsgi.input'].read(request_body_size).decode("utf-8"))


   code = requestBody.get("code", None)

   inputData = requestBody.get("input", "")

   fileName = "/tmp/" + randomStr(5)

   responseData = RunCode(fileName, inputData) if code and WriteCode(code, fileName) else "Error"

   return Response(start_response, {"result": responseData})

完成核心的業(yè)務(wù)邏輯編寫(xiě)之后,我們可以將代碼部署到阿里云函數(shù)計(jì)算中。部署完成之后,我們可以獲得到接口的臨時(shí)測(cè)試地址。通過(guò) PostMan 對(duì)該接口進(jìn)行測(cè)試,以 Python 語(yǔ)言的輸出語(yǔ)句為例:

print('HELLO WORLD')


可以看到,當(dāng)我們通過(guò) POST 方法,攜帶代碼等作為參數(shù),發(fā)起請(qǐng)求后,獲得到的響應(yīng)為:

image


我們通過(guò)響應(yīng)結(jié)果,可以看到,系統(tǒng)是可以正常輸出我們的預(yù)期結(jié)果:“HELLO WORLD” 至此我們完成了標(biāo)準(zhǔn)輸出功能的測(cè)試,接下來(lái)我們對(duì)標(biāo)準(zhǔn)錯(cuò)誤等功能進(jìn)行測(cè)試,此時(shí)我們將剛剛的輸出代碼進(jìn)行破壞:

print('HELLO WORLD)


使用同樣的方法,再次進(jìn)行代碼執(zhí)行,可以看到結(jié)果:


image

結(jié)果中,我們可以看到 Python 的報(bào)錯(cuò)信息,是符合我們的預(yù)期的,至此完成了在線編程功能的標(biāo)準(zhǔn)錯(cuò)誤功能的測(cè)試,接下來(lái),我們進(jìn)行標(biāo)準(zhǔn)輸入功能的測(cè)試,由于我們使用的 subprocess.Popen() 方法,是一種阻塞方法,所以此時(shí)我們需要將代碼和標(biāo)準(zhǔn)輸入內(nèi)容一同放到服務(wù)端。測(cè)試的代碼為:

tempInput = input('please input: ')

print('Output: ', tempInput)


測(cè)試的標(biāo)準(zhǔn)輸入內(nèi)容為:“serverless devs”。


當(dāng)我們使用同樣的方法,發(fā)起請(qǐng)求之后,我們可以看到:


image


系統(tǒng)是正常輸出預(yù)期的結(jié)果。至此我們完成了一個(gè)非常簡(jiǎn)單的在線編程服務(wù)的接口。該接口目前只是初級(jí)版本,僅用于學(xué)習(xí)使用,其具有極大的優(yōu)化空間:


  • 超時(shí)時(shí)間的處理
  • 代碼執(zhí)行完成,可以進(jìn)行清理


當(dāng)然,通過(guò)這個(gè)接口也可以看到這樣一個(gè)問(wèn)題:那就是代碼執(zhí)行過(guò)程中是阻塞的,我們沒(méi)辦法進(jìn)行持續(xù)性的輸入,也沒(méi)有辦法實(shí)時(shí)輸出,即使需要輸入內(nèi)容也是需要將代碼和輸入內(nèi)容一并發(fā)送到服務(wù)端。這種模式和目前市面上常見(jiàn)的 OJ 模式很類似,但是就單純的在線編程而言,還需要進(jìn)一步對(duì)項(xiàng)目?jī)?yōu)化,使其可以通過(guò)非阻塞方法,實(shí)現(xiàn)代碼的執(zhí)行,并且可以持續(xù)性的進(jìn)行輸入操作,持續(xù)性的進(jìn)行內(nèi)容輸出。


更貼近“本地”的代碼執(zhí)行器


我們以一段代碼為例:

import time

print("hello world")

time.sleep(10)

tempInput = input("please: ")

print("Input data: ", tempInput)

當(dāng)我們?cè)诒镜氐膱?zhí)行這段 Python 代碼時(shí),整體的用戶側(cè)的實(shí)際表現(xiàn)是:

  • 系統(tǒng)輸出 hello world
  • 系統(tǒng)等待 10 秒
  • 系統(tǒng)提醒我們 please,我們此時(shí)可以輸入一個(gè)字符串
  • 系統(tǒng)輸出 Input data 以及我們剛剛輸入的字符串

但是,這段代碼如果應(yīng)用于傳統(tǒng) OJ 或者剛剛我們所實(shí)現(xiàn)的在線編程系統(tǒng)中,表現(xiàn)則大不相同:

  • 代碼與我們要輸入內(nèi)容一同傳給系統(tǒng)
  • 系統(tǒng)等待 10 秒
  • 輸出 hello world、please,以及最后輸 Input data 和我們輸入的內(nèi)容


可以看到,OJ 模式上的在線編程功能和本地是有非常大的差距的,至少在體驗(yàn)層面,這個(gè)差距是比較大的。為了減少這種體驗(yàn)不統(tǒng)一的問(wèn)題,我們可以將上上述的架構(gòu)進(jìn)一步升級(jí),通過(guò)函數(shù)的異步觸發(fā),以及 Python 語(yǔ)言的 pexpect.spawn() 方法實(shí)現(xiàn)一款更貼近本地體驗(yàn)的在線編程功能:


image


在整個(gè)項(xiàng)目中,包括了兩個(gè)函數(shù),兩個(gè)存儲(chǔ)桶:


  • 業(yè)務(wù)邏輯函數(shù):該函數(shù)的主要操作是業(yè)務(wù)邏輯,包括創(chuàng)建代碼執(zhí)行的任務(wù)(通過(guò)對(duì)象存儲(chǔ)觸發(fā)器進(jìn)行異步函數(shù)執(zhí)行),以及獲取函數(shù)輸出結(jié)果以及對(duì)任務(wù)函數(shù)的標(biāo)準(zhǔn)輸入進(jìn)行相關(guān)操作等;
  • 執(zhí)行器函數(shù):該函數(shù)的主要作用是執(zhí)行用戶的函數(shù)代碼,這部分是通過(guò)對(duì)象存儲(chǔ)觸發(fā),通過(guò)下載代碼、執(zhí)行代碼、獲取輸入、輸出結(jié)果等;代碼獲取從代碼存儲(chǔ)桶,輸出結(jié)果和獲取輸入從業(yè)務(wù)存儲(chǔ)桶;
  • 代碼存儲(chǔ)桶:該存儲(chǔ)桶的作用是存儲(chǔ)代碼,當(dāng)用戶發(fā)起運(yùn)行代碼的請(qǐng)求, 業(yè)務(wù)邏輯函數(shù)收到用戶代碼后,會(huì)將代碼存儲(chǔ)到該存儲(chǔ)桶,再由該存儲(chǔ)桶處罰異步任務(wù);
  • 業(yè)務(wù)存儲(chǔ)桶:該存儲(chǔ)桶的作用是中間量的輸出,主要包括輸出內(nèi)容的緩存、輸入內(nèi)容的緩存;該部分?jǐn)?shù)據(jù)可以通過(guò)對(duì)象存儲(chǔ)的本身特性進(jìn)行生命周期的制定;

為了讓代碼在線執(zhí)行起來(lái),更加貼近本地體驗(yàn),該方案的代碼分為兩個(gè)函數(shù),分別進(jìn)行業(yè)務(wù)邏輯處理和在線編程核心功能。

其中業(yè)務(wù)邏輯處理函數(shù),主要是:


  • 獲取用戶的代碼信息,生成代碼執(zhí)行 ID,并將代碼存到對(duì)象存儲(chǔ),異步觸發(fā)在線編程函數(shù)的執(zhí)行,返回生成代碼執(zhí)行 ID;
  • 獲取用戶的輸入信息和代碼執(zhí)行 ID,并將內(nèi)容存儲(chǔ)到對(duì)應(yīng)的對(duì)象存儲(chǔ)中;
  • 獲取代碼的輸出結(jié)果,根據(jù)用戶指定的代碼執(zhí)行 ID,將執(zhí)行結(jié)果從對(duì)象存儲(chǔ)中讀取出來(lái),并返回給用戶;


整體的業(yè)務(wù)邏輯為:


image


實(shí)現(xiàn)的代碼為:

# -*- coding: utf-8 -*-


import os

import oss2

import json

import uuid

import random


# 基本配置信息

AccessKey = {

   "id": os.environ.get('AccessKeyId'),

   "secret": os.environ.get('AccessKeySecret')

}


OSSCodeConf = {

   'endPoint': os.environ.get('OSSConfEndPoint'),

   'bucketName': os.environ.get('OSSConfBucketCodeName'),

   'objectSignUrlTimeOut': int(os.environ.get('OSSConfObjectSignUrlTimeOut'))

}


OSSTargetConf = {

   'endPoint': os.environ.get('OSSConfEndPoint'),

   'bucketName': os.environ.get('OSSConfBucketTargetName'),

   'objectSignUrlTimeOut': int(os.environ.get('OSSConfObjectSignUrlTimeOut'))

}


# 獲取獲取/上傳文件到OSS的臨時(shí)地址

auth = oss2.Auth(AccessKey['id'], AccessKey['secret'])

codeBucket = oss2.Bucket(auth, OSSCodeConf['endPoint'], OSSCodeConf['bucketName'])

targetBucket = oss2.Bucket(auth, OSSTargetConf['endPoint'], OSSTargetConf['bucketName'])


# 隨機(jī)字符串

randomStr = lambda num=5: "".join(random.sample('abcdefghijklmnopqrstuvwxyz', num))


# Response

class Response:

   def __init__(self, start_response, response, errorCode=None):

       self.start = start_response

       responseBody = {

           'Error': {"Code": errorCode, "Message": response},

       } if errorCode else {

           'Response': response

       }

       # 默認(rèn)增加uuid,便于后期定位

       responseBody['ResponseId'] = str(uuid.uuid1())

       self.response = json.dumps(responseBody)


   def __iter__(self):

       status = '200'

       response_headers = [('Content-type', 'application/json; charset=UTF-8')]

       self.start(status, response_headers)

       yield self.response.encode("utf-8")


def handler(environ, start_response):

   try:

       request_body_size = int(environ.get('CONTENT_LENGTH', 0))

   except (ValueError):

       request_body_size = 0

   requestBody = json.loads(environ['wsgi.input'].read(request_body_size).decode("utf-8"))


   reqType = requestBody.get("type", None)


   if reqType == "run":

       # 運(yùn)行代碼

       code = requestBody.get("code", None)

       runId = randomStr(10)

       codeBucket.put_object(runId, code.encode("utf-8"))

       responseData = runId

   elif reqType == "input":

       # 輸入內(nèi)容

       inputData = requestBody.get("input", None)

       runId = requestBody.get("id", None)

       targetBucket.put_object(runId + "-input", inputData.encode("utf-8"))

       responseData = 'ok'

   elif reqType == "output":

       # 獲取結(jié)果

       runId = requestBody.get("id", None)

       targetBucket.get_object_to_file(runId + "-output", '/tmp/' + runId)

       with open('/tmp/' + runId) as f:

           responseData = f.read()

   else:

       responseData = "Error"


   return Response(start_response, {"result": responseData})

執(zhí)行器函數(shù),主要是通過(guò)代碼存儲(chǔ)桶觸發(fā),從而進(jìn)行代碼執(zhí)行的模塊,這一部分主要包括:


  • 從存儲(chǔ)桶獲取代碼,并通過(guò) pexpect.spawn() 進(jìn)行代碼執(zhí)行;
  • 通過(guò) pexpect.spawn().read_nonblocking() 非阻塞的獲取間斷性的執(zhí)行結(jié)果,并寫(xiě)入到對(duì)象存儲(chǔ);
  • 通過(guò) pexpect.spawn().sendline() 進(jìn)行內(nèi)容輸入;


整體流程為:


image


代碼實(shí)現(xiàn)為:


# -*- coding: utf-8 -*-


import os

import re

import oss2

import json

import time

import pexpect


# 基本配置信息

AccessKey = {

   "id": os.environ.get('AccessKeyId'),

   "secret": os.environ.get('AccessKeySecret')

}


OSSCodeConf = {

   'endPoint': os.environ.get('OSSConfEndPoint'),

   'bucketName': os.environ.get('OSSConfBucketCodeName'),

   'objectSignUrlTimeOut': int(os.environ.get('OSSConfObjectSignUrlTimeOut'))

}


OSSTargetConf = {

   'endPoint': os.environ.get('OSSConfEndPoint'),

   'bucketName': os.environ.get('OSSConfBucketTargetName'),

   'objectSignUrlTimeOut': int(os.environ.get('OSSConfObjectSignUrlTimeOut'))

}


# 獲取獲取/上傳文件到OSS的臨時(shí)地址

auth = oss2.Auth(AccessKey['id'], AccessKey['secret'])

codeBucket = oss2.Bucket(auth, OSSCodeConf['endPoint'], OSSCodeConf['bucketName'])

targetBucket = oss2.Bucket(auth, OSSTargetConf['endPoint'], OSSTargetConf['bucketName'])



def handler(event, context):

   event = json.loads(event.decode("utf-8"))


   for eveEvent in event["events"]:


       # 獲取object

       code = eveEvent["oss"]["object"]["key"]

       localFileName = "/tmp/" + event["events"][0]["oss"]["object"]["eTag"]


       # 下載代碼

       codeBucket.get_object_to_file(code, localFileName)


       # 執(zhí)行代碼

       foo = pexpect.spawn('python %s' % localFileName)


       outputData = ""


       startTime = time.time()


       # timeout可以通過(guò)文件名來(lái)進(jìn)行識(shí)別

       try:

           timeout = int(re.findall("timeout(.*?)s", code)[0])

       except:

           timeout = 60


       while (time.time() - startTime) / 1000 <= timeout:

           try:

               tempOutput = foo.read_nonblocking(size=999999, timeout=0.01)

               tempOutput = tempOutput.decode("utf-8", "ignore")


               if len(str(tempOutput)) > 0:

                   outputData = outputData + tempOutput


               # 輸出數(shù)據(jù)存入oss

               targetBucket.put_object(code + "-output", outputData.encode("utf-8"))


           except Exception as e:


               print("Error: ", e)


               # 有輸入請(qǐng)求被阻塞

               if str(e) == "Timeout exceeded.":


                   try:

                       # 從oss讀取數(shù)據(jù)

                       targetBucket.get_object_to_file(code + "-input", localFileName + "-input")

                       targetBucket.delete_object(code + "-input")

                       with open(localFileName + "-input") as f:

                           inputData = f.read()

                       if inputData:

                           foo.sendline(inputData)

                   except:

                       pass


               # 程序執(zhí)行完成輸出

               elif "End Of File (EOF)" in str(e):

                   targetBucket.put_object(code + "-output", outputData.encode("utf-8"))

                   return True


               # 程序拋出異常

               else:


                   outputData = outputData + "\n\nException: %s" % str(e)

                   targetBucket.put_object(code + "-output", outputData.encode("utf-8"))


                   return False

當(dāng)我們完成核心的業(yè)務(wù)邏輯編寫(xiě)之后,我們可以將項(xiàng)目部署到線上。

項(xiàng)目部署完成之后,和上文的測(cè)試方法一樣,在這里也通過(guò) PostMan 對(duì)接口進(jìn)行測(cè)試。此時(shí),我們需要設(shè)定一個(gè)覆蓋能較全的測(cè)試代碼,包括輸出打印、輸入、一些 sleep() 等方法:

image


當(dāng)我們通過(guò) PostMan 發(fā)起請(qǐng)求執(zhí)行這段代碼之后,我們可以看到系統(tǒng)為我們返回了預(yù)期的代碼執(zhí)行 ID:


image


我們可以看到系統(tǒng)會(huì)返回給我們一個(gè)代碼執(zhí)行 ID,該執(zhí)行 ID 將會(huì)作為我們整個(gè)請(qǐng)求任務(wù)的 ID,此時(shí),我們可以通過(guò)獲取輸出結(jié)果的接口,來(lái)獲取結(jié)果:


image


由于代碼中有:

time.sleep(10)


所以,迅速獲得結(jié)果的時(shí)候是看不到后半部分的輸出結(jié)果,我們可以設(shè)置一個(gè)輪訓(xùn)任務(wù),不斷通過(guò)該 ID 對(duì)接口進(jìn)行刷新:

image


可以看到,10 秒鐘后,代碼執(zhí)行到了輸入部分:

tempInput = input('please: ')

此時(shí),我們?cè)偻ㄟ^(guò)輸入接口,進(jìn)行輸入操作:


image


完成之后,我們可以看到輸入成功(result: ok)的結(jié)果,此時(shí)我們繼續(xù)刷新之前獲取結(jié)果部分的請(qǐng)求:


image


可以看到,我們已經(jīng)獲得到了所有結(jié)果的輸出。


相對(duì)于上文的在線編程功能,這種“更貼近本地的代碼執(zhí)行器“變得復(fù)雜了很多,但是在實(shí)際使用的過(guò)程中,卻可以更好的模擬出本地執(zhí)行代碼時(shí)的一些現(xiàn)象,例如代碼的休眠、阻塞、內(nèi)容的輸出等。

總結(jié)


無(wú)論是簡(jiǎn)單的在線代碼執(zhí)行器部分,還是更貼近“本地”的代碼執(zhí)行器部分,這篇文章在所應(yīng)用的內(nèi)容是相對(duì)廣泛的。通過(guò)這篇文章你可以看到:


  • HTTP 觸發(fā)器的基本使用方法;對(duì)象存儲(chǔ)觸發(fā)器的基本使用方;
  • 函數(shù)計(jì)算組件、對(duì)象存儲(chǔ)組件的基本使用方法,組件間依賴的實(shí)現(xiàn)方法;

同時(shí),通過(guò)這篇文章,也可以從一個(gè)側(cè)面看到這樣一個(gè)常見(jiàn)問(wèn)題的簡(jiǎn)單解答:我有一個(gè)項(xiàng)目,我是每個(gè)接口一個(gè)函數(shù),還是多個(gè)接口復(fù)用一個(gè)函數(shù)?


針對(duì)這個(gè)問(wèn)題,其實(shí)最主要的是看業(yè)務(wù)本身的訴求,如果多個(gè)接口表達(dá)的含義是一致的,或者是同類的,類似的,并且多個(gè)接口的資源消耗是類似的,那么放在一個(gè)函數(shù)中來(lái)通過(guò)不同的路徑進(jìn)行區(qū)分是完全可以的;如果出現(xiàn)資源消耗差距較大,或者函數(shù)類型、規(guī)模、類別區(qū)別過(guò)大的時(shí)候,將多個(gè)接口放在多個(gè)函數(shù)下也是沒(méi)有問(wèn)題的。


本文實(shí)際上是拋磚引玉,無(wú)論是 OJ 系統(tǒng)的“判題機(jī)”部分,還是在線編程工具的“執(zhí)行器部分”,都可以很好的和 Serverless 架構(gòu)有著比較有趣的結(jié)合點(diǎn)。這種結(jié)合點(diǎn)不僅僅可以解決傳統(tǒng)在線編程所頭疼的事情(安全問(wèn)題,資源消耗問(wèn)題,并發(fā)問(wèn)題,流量不穩(wěn)定問(wèn)題),更可以將 Serverless 的價(jià)值在一個(gè)新的領(lǐng)域發(fā)揮出來(lái)。