ในบทความก่อนหน้าของฉันฉันสร้างเว็บไซต์คงที่พร้อมตอบสนองและงูหลามแล้วประเด็นของความยืดหยุ่น ในบทความนี้ ผมขอแนะนำWeb Workersเพื่อเรียกใช้โค้ด Python ในเธรดของตัวเอง ซึ่งทำให้เธรด UI ว่างขึ้น คุณสามารถค้นหารหัสที่มาที่นี่และเว็บไซต์คงที่บนหน้า GitHub ที่นี่
โซลูชันก่อนหน้านี้ของฉันทำงานได้ดีสำหรับงานง่ายๆ ในการสร้างเมทริกซ์ แต่ถ้าฉันทำอะไรที่แพงในการคำนวณ มันจะบล็อกเธรด UI และแอปจะไม่ตอบสนองจนกว่าการคำนวณจะส่งคืน ฉันต้องเรียกใช้รหัสหลามในเธรดอื่น ในเบราว์เซอร์ ทำได้โดยใช้ "web worker"
เอกสาร pyodideสำหรับเรื่องนี้มีความชัดเจนมากปัญหาหลักคือวิธีการเสียบเข้ากับการตอบสนอง ปัญหาคือว่าตอบสนองการใช้งานการสร้างกระบวนการwebpackการรวมกลุ่มไฟล์ที่มาของแต่ละบุคคลทั้งหมดเป็นไฟล์ขนาดใหญ่น้อย แต่วัตถุที่คนงานต้องใช้ JavaScript แฟ้มที่มีชื่ออยู่ในนั้นของคอนสตรัค มีแพ็คเกจโอเพ่นซอร์สสองสามตัวที่จะจัดการกับสิ่งนี้ ฉันเลือกworker-loaderเนื่องจากเป็นแพ็คเกจ contrib สำหรับ "webpack" และจะเป็นส่วนหนึ่งของการแจกจ่ายฐานถัดไป
เราสามารถเพิ่มไปยังโครงการก่อนหน้าได้ตามปกติ:
npm install --save worker-loader
import PythonWorker from 'worker-loader!./pythonWorker.js' // eslint-disable-line import/no-webpack-loader-syntax
ตอนนี้ฉันต้องการวิธีเรียกรหัสในตัวพนักงาน การสื่อสารกับผู้ปฏิบัติงานเกิดขึ้นผ่านการเผยแพร่และสมัครรับ "ข้อความ" ซึ่งเป็นออบเจ็กต์ JavaScript อย่างง่าย แทนที่จะเขียนข้อความพิเศษสำหรับแต่ละฟังก์ชัน ฉันเลือกใช้comlink package ซึ่งสร้าง wrapper รอบ ๆ การเชื่อมต่อเพื่อให้สามารถเรียกใช้ฟังก์ชันอย่างง่ายได้
npm install --save comlink
import * as Comlink from 'comlink/dist/esm/comlink'
self.importScripts('https://cdn.jsdelivr.net/pyodide/v0.17.0/full/pyodide.js')
const PYTHON_CODE = `
import random
import numpy as np
def generate_matmul_exercise(max_rows, max_cols):
m = random.randint(1, max_rows)
n = random.randint(1, max_cols)
p = random.randint(1, max_cols)
rng = np.random.default_rng()
A = rng.integers(low=-10, high=10, size=(m, n), dtype=np.int32)
B = rng.integers(low=-10, high=10, size=(n, p), dtype=np.int32)
C = A @ B
return {
'm': m,
'n': n,
'p': p,
'A': A,
'B': B,
'C': C
}
def generate_matadd_exercise(max_rows, max_cols):
m = random.randint(1, max_rows)
n = random.randint(1, max_cols)
rng = np.random.default_rng()
A = rng.integers(low=-10, high=10, size=(m, n), dtype=np.int32)
B = rng.integers(low=-10, high=10, size=(m, n), dtype=np.int32)
C = A + B
return {
'm': m,
'n': n,
'A': A,
'B': B,
'C': C
}
`
function wrapGenerateMatmulExercise() {
const func = self.pyodide.globals.get('generate_matmul_exercise') // eslint-disable-line no-restricted-globals
return (maxNumberOfRows, maxNumberOfColumns) => {
console.log('generateMatmulExercise')
const obj = func(maxNumberOfRows, maxNumberOfColumns)
const results = {
m: obj.get('m'),
n: obj.get('n'),
p: obj.get('p'),
A: obj
.get('A')
.toJs()
.map((x) => Array.from(x)),
B: obj
.get('B')
.toJs()
.map((x) => Array.from(x)),
C: obj
.get('C')
.toJs()
.map((x) => Array.from(x))
}
obj.destroy()
return results
}
}
function wrapGenerateMataddExercise() {
const func = self.pyodide.globals.get('generate_matadd_exercise') // eslint-disable-line no-restricted-globals
return (maxNumberOfRows, maxNumberOfColumns) => {
const obj = func(maxNumberOfRows, maxNumberOfColumns)
const results = {
m: obj.get('m'),
n: obj.get('n'),
A: obj
.get('A')
.toJs()
.map((x) => Array.from(x)),
B: obj
.get('B')
.toJs()
.map((x) => Array.from(x)),
C: obj
.get('C')
.toJs()
.map((x) => Array.from(x))
}
obj.destroy()
return results
}
}
async function loadPyodideAndPackages() {
await self.loadPyodide({
indexURL: 'https://cdn.jsdelivr.net/pyodide/v0.17.0/full/'
}) // eslint-disable-line no-restricted-globals
await self.pyodide.loadPackage(['numpy']) // eslint-disable-line no-restricted-globals
self.pyodide.runPython(PYTHON_CODE) // eslint-disable-line no-restricted-globals
}
const pyodideReadyPromise = loadPyodideAndPackages()
const pythonContext = {
async setup() {
await pyodideReadyPromise
this.generateMatmulExercise = wrapGenerateMatmulExercise()
this.generateMataddExercise = wrapGenerateMataddExercise()
}
}
Comlink.expose(pythonContext)
เนื่องจากโค้ดจะถูกรันในเธรดที่แยกจากกัน ฟังก์ชัน Python จึงไม่จำเป็นต้องเป็น "async" อีกต่อไป และการรอและ asyncs จะถูกลบออกจากโค้ดของ wrapper
ก่อนหน้านี้ ฉันเคยใช้แท็กสคริปต์ใน "public/index.html" เพื่อนำเข้าโค้ด pyodide อย่างไรก็ตาม สิ่งนี้จะไม่สามารถใช้ได้กับเธรดของผู้ปฏิบัติงาน เพื่อจัดการกับสิ่งนี้ ฉันจะลบแท็กสคริปต์และเพิ่มself.importScriptsไปที่จุดเริ่มต้นของรหัสผู้ปฏิบัติงาน สังเกตการใช้selfเพื่อเข้าถึงบริบทส่วนกลางของผู้ปฏิบัติงาน
สุดท้ายบล็อกของโค้ดในตอนท้ายหลังจากที่ wrappers โหลด pyodide WebAssembly, แพ็คเกจ numpy และโค้ด Python ในเครื่อง ในที่สุดฉันก็สร้างpythonContextวัตถุซึ่งถูกห่อด้วย comlink เริ่มแรกอ็อบเจ็กต์นี้มีฟังก์ชันอะซิงโครนัสเดียวsetup.เมื่อเรียกสิ่งนี้ว่ารอให้การเริ่มต้นไพโอไดด์เสร็จสมบูรณ์ ฟังก์ชันจะเพิ่มฟังก์ชันลงในอ็อบเจ็กต์ที่ห่อ
ขั้นตอนสุดท้ายคือการสร้างผู้ปฏิบัติงานใน “src/App.js” ทั้งหมดนี้จำเป็นต้องมีการเปลี่ยนแปลงเล็กน้อยของcomponentDidMountฟังก์ชัน
async componentDidMount() {
const pythonWorker = Comlink.wrap(new PythonWorker())
await pythonWorker.setup()
this.setState({ pythonWorker })
}
npm start
บทนำ โรคหลอดเลือดสมองเป็นเหตุฉุกเฉินทางการแพทย์ที่สามารถส่งผลกระทบต่อทุกคนได้ตลอดเวลา เกิดขึ้นเมื่อการไหลเวียนของเลือดไปยังส่วนหนึ่งของสมองหยุดชะงัก นำไปสู่การสูญเสียการทำงานของสมองอย่างกะทันหัน
คุณต้องเคยได้ยินเกี่ยวกับปลั๊กอิน ChatGPT อันทรงพลังใหม่ทั้งหมด เช่น เบราว์เซอร์ ตัวแปลรหัส ฯลฯ แต่มีปัญหา การเข้าถึงปลั๊กอินถูกจำกัดไว้เฉพาะรายการรอ และหลายคนไม่สามารถเข้าถึงได้
“หวัดดี Siri เล่น Me Dive โดย Olivia Dean” ในเดือนพฤษภาคม 2021 ฉันเริ่มฝึกงานที่ Future Academy Africa ในเมือง Akure ประเทศไนจีเรีย
เมื่อคุณส่งคำขอไปที่ facebook.com คอมพิวเตอร์ของคุณจะค้นหาชื่อโดเมนเพื่อแปลชื่อโดเมนนั้นเป็นที่อยู่ IP เพื่อให้คอมพิวเตอร์ของคุณสามารถเชื่อมต่อได้
เมื่อคุณโตขึ้น คุณมักจะได้รับการบอกว่าโลกเป็นอย่างที่มันเป็น และชีวิตของคุณก็แค่ใช้ชีวิตอยู่ในโลก ไม่เสี่ยงชีวิต แค่เดินตามเส้นทางที่กำหนดและตายในที่สุด และพยายามอย่า ทุบกำแพงมากเกินไป แต่นั่นเป็นชีวิตที่จำกัดมาก
คุณสามารถเป็น OSINT Investigator, CTF Player หรือเพียงแค่ใครก็ตามที่ได้รับสายสแปม ผู้ที่พยายามยืนยันหมายเลขที่คุณเห็นในโฆษณา