{ "version": "https://jsonfeed.org/version/1", "title": "Ruby", "description": "A dynamic, interpreted, open source programming language with a focus on simplicity and productivity.", "home_page_url": "go/ruby", "feed_url": "feed/ruby.json", "icon": "https://cdn.v2ex.com/navatar/0504/9e90/367_large.png?m=1579009612", "favicon": "https://cdn.v2ex.com/navatar/0504/9e90/367_normal.png?m=1579009612", "items": [ { "author": { "url": "member/mizuhashi", "name": "mizuhashi", "avatar": "https://cdn.v2ex.com/avatar/8854/0e78/157347_large.png?m=1774621158" }, "url": "t/1195605", "date_modified": "2026-03-03T23:15:50+00:00", "content_html": "

DIDComm\u662f\u4e00\u500b\u57fa\u65bc W3C DID \uff08\u53bb\u4e2d\u5fc3\u5316 ID \uff09\u7684\u901a\u4fe1\u5354\u8b70\u3002\u5982\u679c\u4e00\u500b\u670d\u52d9\u5668\u60f3\u548c\u53e6\u4e00\u500b\u5be6\u73fe\u4e86 DIDComm \u7684\u670d\u52d9\u5668\u901a\u4fe1\uff0c\u5b83\u6703\u9700\u8981\u5728/.well-known/did.json \u63d0\u4f9b\u4e00\u500b DID \u6587\u6a94\uff0c\u6587\u6a94\u88cf\u5305\u542b\u4e86\u516c\u9470\u4ee5\u53ca DIDComm \u7684 service endpoint \u3002\u6211\u7684 demo \u670d\u52d9\u5668\u7684 DID \u6587\u6a94\u9577\u9019\u6a23\uff1a https://dc.mbkr.ca/.well-known/did.json \u3002

\n

\u64c1\u6709\u4e86\u9019\u500b\u6587\u6a94\u4e4b\u5f8c\uff0cdid:web:dc.mbkr.ca \u9019\u500b DID \u5c31\u6703\u5c0d\u61c9\u6211\u7684\u670d\u52d9\u5668\uff0c\u4f60\u53ea\u9700\u8981\u9019\u500b id \u5c31\u53ef\u4ee5\u7d66\u6211\u767c\u4fe1\u606f\uff0c\u767c\u4fe1\u65b9\u6703\u6839\u64da\u9019\u500b id \u89e3\u6790\u5230 DID \u6587\u6a94\uff0c\u7372\u53d6\u516c\u9470\u69cb\u5efa\u4fe1\u606f\uff0c\u4e26\u63a8\u5230 service endpoint \u4e0a\u3002

\n

\u6211\u4e5f\u505a\u4e86\u4e00\u500b\u516c\u958b\u7684 demo \u670d\u52d9\u5668\uff0chttps://dc-public.mbkr.ca/ \uff0c\u4f60\u53ef\u4ee5\u7528public\u505a\u5bc6\u78bc\u767b\u9304\u3002

\n

Demo \u7684 repo: https://github.com/onyxblade/didcomm-rails-demo

\n

\u5be6\u73fe\u4e0a\uff0c\u6211\u672c\u4f86\u662f\u8b93 AI \u751f\u6210\u4e86\u4e00\u500b Ruby \u7248\u672c\u7684 DIDComm \u5be6\u73fe\uff0c\u4e0d\u904e\u5bc6\u78bc\u5b78\u7684\u5167\u5bb9\u5f88\u591a\uff0c\u6211\u6700\u5f8c\u9084\u662f\u6c7a\u5b9a\u76f4\u63a5\u7528didcomm-rust\u9019\u500b\u6a19\u6e96\u7684\u53c3\u8003\u5be6\u73fe\u3002\u9019\u500b Rust \u7684\u5be6\u73fe\u53ef\u4ee5\u8f38\u51fa wasm \uff0c\u4f46 wasmtime-rb \u597d\u50cf\u9084\u6c92\u6210\u719f\u5230\u80fd\u76f4\u63a5\u7528\uff0c\u6240\u4ee5\u6700\u7d42\u6211\u505a\u4e86\u4e00\u500b HTTP \u670d\u52d9\u5668didcomm-http\uff0c\u4f86\u628a wasm \u63a5\u53e3\u5305\u88dd\u6210 HTTP API \u3002

\n

Happy Hacking!

\n", "date_published": "2026-03-03T23:15:27+00:00", "title": "\u4e00\u500b\u7528 DIDComm \u5be6\u73fe\u670d\u52d9\u5668\u9593\u901a\u4fe1\u7684 Rails demo", "id": "t/1195605" }, { "author": { "url": "member/Kauruus", "name": "Kauruus", "avatar": "https://cdn.v2ex.com/avatar/1c6c/41b9/328201_large.png?m=1531401751" }, "url": "t/1094035", "title": "RubyConf China 2024 \u53c2\u4f1a\u62a5\u544a - Day 1", "id": "t/1094035", "date_published": "2024-11-30T17:15:22+00:00", "content_html": "

Rails + Next.js\uff1a\u4e00\u79cd\u63d0\u5347\u5f00\u53d1\u8005\u548c\u7528\u6237\u4f53\u9a8c\u7684\u5f00\u53d1\u67b6\u6784\u8303\u5f0f

\n

Rails \u5199\u540e\u7aef\u975e\u5e38\u723d\uff0c\u4f46\u662f\u5199\u524d\u7aef\u5c31\u5f88\u75db\u82e6\uff0c\u4e8e\u662f\u62c9\u4e0a\u4f53\u9a8c\u66f4\u597d\u7684 Next.js \uff0c\u76f4\u63a5\u6709\u5b8c\u5584\u7684\u7ec4\u4ef6\u3001IDE \u548c\u793e\u533a\u652f\u6301\uff0c\u7ec4\u5408\u6210 Next.js \u4ee3\u7406 API \u8bf7\u6c42\u5230 Rails \u7684\u67b6\u6784\u3002

\n

\u6f14\u8bb2\u8005\u8fd8\u63d0\u5230\u4e00\u4e2a\u597d\u5904\uff0c\u5c31\u662f Rails \u57fa\u4e8e cookie \u7684 session \u7ba1\u7406\u975e\u5e38\u5b8c\u5584\uff0c\u901a\u8fc7\u8fd9\u4e2a\u67b6\u6784\u5c31\u53ef\u4ee5\u91cd\u7528\u8fd9\u90e8\u5206\uff0c\u800c\u4e0d\u9700\u8981\u641e\u4ec0\u4e48 JWT token \u3002\u4f46\u662f\u4ece\u6f14\u8bb2\u91cc\u770b\uff0cNext.js \u548c Rails \u4e4b\u95f4\u4ea4\u4e92\u4e5f\u6ca1\u7279\u522b\u65b9\u4fbf\uff0c\u4f8b\u5982 Rails \u8981\u5173\u6389 CSRF token \u4e4b\u7c7b\u7684\u4e1c\u897f\uff0c\u8fd9\u53cd\u800c\u53ef\u80fd\u88ab\u5229\u7528\u3002

\n

\u8fd9\u7c7b\u6d89\u53ca\u524d\u540e\u7aef\u5f00\u53d1\u7684\u95ee\u9898\uff0c\u80af\u5b9a\u53c8\u626f\u51fa\u524d\u540e\u7aef\u5206\u79bb\u3001\u56e2\u961f\u642d\u5efa\u7684\u95ee\u9898\u3002\u6211\u81ea\u5df1\u5f88\u4e45\u6ca1\u5199\u524d\u7aef\u4e86\uff0c\u6240\u6709\u662f\u504f\u5411\u4e8e\u5206\u5f00\u7684\uff0c\u4f46\u662f\u5f88\u591a Rails KOL \u90fd\u559c\u6b22\u5168\u6808\u7684\u611f\u89c9\u3002

\n

\u5341\u500d\u6027\u80fd\u63d0\u5347\uff0c\u539f\u751f Ruby \u5f02\u6b65\u7f16\u7a0b\u673a\u5236\u7684\u601d\u8003\u4e0e\u5e94\u7528

\n

\u8fd9\u662f\u6211\u633a\u671f\u5f85\u7684\u4e00\u4e2a\u4e3b\u9898\uff0c\u6211\u8fd8\u505a\u4e86\u529f\u8bfe\uff0c\u53bb\u770b\u4e86 Fiber scheduler, evt, async \uff0c\u6d4b\u8bd5\u4e86\u7528 falcon \u8dd1 Rails \u7684\u6027\u80fd\u3002

\n

\u6f14\u8bb2\u8005\u5f15\u5165\u5f02\u6b65\u7684\u539f\u56e0\u662f\u56e0\u4e3a LLM API \u54cd\u5e94\u6162\uff0c\u6240\u6709\u5982\u679c\u4e0d\u5f02\u6b65\uff0c\u90a3\u53d1\u4e2a API \u8bf7\u6c42\u5c31\u8981\u963b\u585e\u4e00\u4e2a\u7ebf\u7a0b\uff0c\u6240\u4ee5\u5f02\u6b65\u52bf\u5728\u5fc5\u884c\uff0c\u4e3e\u7684\u4f8b\u5b50\u4e5f\u4e3b\u8981\u662f\u7528 Fiber \u505a\u5f02\u6b65 API \u8bf7\u6c42\uff0c\u4f46\u6ca1\u7ec6\u8bb2\uff08\u6216\u8005\u672c\u6765\u5c31\u4e0d\u503c\u4e00\u8bb2\u5427\uff09\u3002\u6f14\u8bb2\u8005\u79f0 LLM \u5e26\u6765\u4e86\u7f16\u7a0b\u8303\u5f0f\u7684\u8f6c\u6362\uff0c\u5176\u4e2d\u5305\u62ec\u4ece CPU \u5bc6\u96c6\u578b\u53d8\u6210\u4e86 IO \u5ef6\u8fdf\u5f0f\uff0c\u8fd9\u5c31\u6709\u70b9\u5f3a\u884c\u4e86\u3002\u540e\u9762\u5c31\u662f\u7b80\u5355\u7684 Fiber \u4ecb\u7ecd\uff0c\u548c async/await, promise, goroutine \u7684\u5bf9\u6bd4\uff0c\u8fc7\u4e8e\u7b80\u5355\uff0c\u5c31\u5217\u8868\u683c\u8bb2\u4e2a\u6982\u5ff5\u3002

\n

\u6211\u662f\u633a\u5931\u671b\u7684\u3002\u6807\u9898\u53f7\u79f0\u5341\u500d\u6027\u80fd\u63d0\u5347\uff0c\u6211\u5e0c\u671b\u662f\u6709\u6570\u636e\u652f\u6491\u7684\uff0c\u4f46\u662f\u6ca1\u6709\u3002\u5bf9\u673a\u5236\u7684\u601d\u8003\uff0c\u6211\u4ee5\u4e3a\u4f1a\u8bb2 Fiber \u548c Fiber scheduler \u7684\u539f\u7406\uff0c\u4f46\u8fd9\u4e9b\u90fd\u7b80\u5355\u5e26\u8fc7\u4e86\u3002\u800c\u5e94\u7528\u4e5f\u53ea\u6709 API \u8bf7\u6c42\u5f02\u6b65\u5316\uff08\u8fd8\u5f88\u592a\u5feb\u7ffb\u8fc7\u7684 concurrency gem \u4f8b\u5b50\uff0c\u770b\u4e0d\u6e05\u554a\uff09\u3002

\n

\u5c31\u5f53\u629b\u7816\u5f15\u7389\u5427\uff0c\u6700\u540e\u547c\u5401\u5927\u5bb6\u6765\u5171\u5efa Ruby \u7684 LLM \u548c\u5f02\u6b65\u751f\u6001\u3002

\n

SDB: a New Ruby Stack Profiling Tool

\n

\u4e00\u4e2a\u65b0\u7684 stack profiler \uff0c\u5728 ruby \u8fdb\u7a0b\u5185\u901a\u8fc7\u4e00\u4e2a\u72ec\u7acb\u7ebf\u7a0b\u626b\u63cf ruby \u7684\u8c03\u7528\u6808\uff0c\u4f46\u4e0d\u83b7\u53d6 GVL \u6240\u4ee5\u57fa\u672c\u4e0d\u5f71\u54cd\u5e94\u7528\u6027\u80fd\u3002\u6709 data race \u7684\u98ce\u9669\uff0c\u4f46\u4e00\u70b9\u9519\u8bef\u4e0d\u5f71\u54cd\u6027\u80fd\u5206\u6790\u7684\u76ee\u6807\u3002\u51fd\u6570\u5730\u5740\u548c\u6587\u4ef6\u540d/\u51fd\u6570\u540d\u7684\u5173\u7cfb\u662f\u901a\u8fc7 ebpf \u7684 uprobe/uretprobe \u8bb0\u5f55\u7684\uff0c\u53ea\u5728\u65b9\u6cd5\u88ab\u5b9a\u4e49\u7684\u65f6\u5019\u4f1a\u8bb0\u5f55,\u4e0d\u7528\u91cd\u590d\u89e3\u6790\u3002

\n

\u8fd9\u4e2a\u6f14\u8bb2\u7684\u51c6\u5907\u5c31\u975e\u5e38\u597d\uff0c\u63d0\u51fa\u95ee\u9898\uff0c\u5206\u6790\u73b0\u6709\u65b9\u6848\u7684\u7f3a\u70b9\uff0c\u63d0\u51fa\u6539\u8fdb\u8bbe\u8ba1\u548c\u76ee\u6807\uff0c\u901a\u8fc7\u6027\u80fd\u5bf9\u6bd4\u8bc1\u660e\u8bbe\u8ba1\u7684\u53ef\u884c\u6027\u3002

\n

\u4e0b\u4e00\u4e2a\u5341\u5e74\u7684 Modern Monolith

\n

\u8fd9\u91cc\u7684 monolith \uff0c\u662f\u6307\u524d\u540e\u7aef\u653e\u4e00\u8d77\uff0c\u6240\u4ee5\u548c\u7b2c\u4e00\u4e2a\u4e3b\u9898\u662f\u7c7b\u4f3c\u7684\uff0c\u5c31\u662f\u4e3a\u4e86\u66f4\u597d\u5730\u5728 Rails \u9879\u76ee\u91cc\u5199\u524d\u7aef\u4ee3\u7801\u3002

\n

\u901a\u8fc7\u4e00\u4e2a Todo list \u7684\u5e94\u7528\uff0c\u5206\u522b\u6f14\u793a Hotwire, ViewComponent, Inertia.js \u7684\u65b9\u6848\u3002\u4f5c\u4e3a demo \u6211\u89c9\u5f97\u633a\u5931\u8d25\u7684\uff0c\u6ca1\u6709\u771f\u5b9e\u6f14\u793a\uff0c\u53ea\u6709\u622a\u56fe\uff0c\u89c6\u56fe\u4ee3\u7801\u4e5f\u590d\u6742\uff0c\u5c5e\u4e8e\u4e0d\u61c2\u7684\u5b8c\u5168\u5c31\u8ddf\u4e0d\u4e0a\u7684\u7c7b\u578b\uff0c\u5927\u90e8\u5206\u53ea\u662f\u6d6a\u8d39\u65f6\u95f4\uff0c\u8fd8\u597d Inertia.js \u662f\u8bb2\u6e05\u695a\u539f\u7406\u7684\u3002

\n

\u6700\u540e\u4e5f\u6709\u89c2\u4f17\u95ee\u4e86 monolith \u7684\u5b9a\u4e49\u95ee\u9898\uff0c\u5728\u4e00\u4e2a Raisl \u5e94\u7528\u91cc\u6709\u591a\u4e2a\u9886\u57df\u7684\uff08\u6ca1\u62c6\u6210\u5fae\u670d\u52a1\uff09\uff0c\u4f46\u505a\u4e86\u524d\u540e\u7aef\u5206\u79bb\u8fd8\u7b97\u4e0d\u7b97 monolith \u3002\u6f14\u8bb2\u8005\u8bf4\u662f\u4f60\u5e94\u7528\u4e1a\u52a1\u903b\u8f91\u81a8\u80c0\uff0c\u8fd9\u90fd\u4e0d\u80fd\u7b97\u662f\u6280\u672f\u95ee\u9898\u4e86\uff08\u5927\u610f\u5982\u6b64\uff09\u3002

\n

Metasploit \u4e0e Ruby

\n

\u975e\u5e38\u201c\u5c0f\u4f17\u201c\u7684\u4e3b\u9898\uff0c\u6f14\u8bb2\u8005\u4e5f\u505a\u4e86\u5f88\u591a\u51c6\u5907\uff0cPPT \u585e\u4e86\u5f88\u591a\u5185\u5bb9\uff0c,Metasploit \u5386\u53f2\uff0c\u67b6\u6784\uff0c\u73af\u5883\uff0cTruffleRuby \u4ec0\u4e48\u90fd\u6709\u3002\u4f46\u662f\u6f14\u8bb2\u6548\u679c\u4e0d\u592a\u597d\uff0c\u8bed\u901f\u98de\u5feb\uff0c\u6211\u53ea\u80fd\u542c\u4e2a\u5927\u6982\uff0c\u611f\u89c9\u5185\u5bb9\u90fd\u662f\u873b\u8713\u70b9\u6c34\uff0c\u7ed3\u679c\u5c31\u662f\u4ec0\u4e48\u90fd\u6ca1\u5b66\u5230\u3002

\n

\u6784\u5efa\u57fa\u4e8e LLM \u7684\u8bed\u97f3\u673a\u5668\u4eba

\n

Demo \u6548\u679c\u975e\u5e38\u597d\uff0c\u4e5f\u5206\u4eab\u4e86\u5f88\u591a\u5de5\u7a0b\u4e0a\u7684\u5b9e\u8df5\uff0c\u5982\u5206\u5c42\u7684\u67b6\u6784\uff08 ASR + TTS, turn-taking, LLM)\uff0c\u72b6\u6001\u7684\u7ba1\u7406\uff0c\u6d41\u5f0f\u6027\u80fd\u4f18\u5316\uff0cprompt \uff0ctool calling \uff0c\u5bf9\u751f\u6210\u5185\u5bb9\u7684\u4f18\u5316\u2026\u2026\u5177\u4f53\u8fd8\u662f\u770b\u56de\u653e\u5427\u3002

\n

\u6fc0\u8d77\u4e86\u6211\u5bf9 LLM \u5f00\u53d1\u7684\u5174\u8da3\u3002

\n

\u800c\u4e14\u770b\u4ee3\u7801\u5176\u5b9e\u662f Go \u5b9e\u73b0\u7684\uff0c\u6ca1\u6709 API \u963b\u585e\u7ebf\u7a0b\u7684\u95ee\u9898\u3002\u72b6\u6001\u673a\uff08\u6f14\u8bb2\u8005\u628a\u5b83\u53eb Routine \uff09\u7684\u5b9e\u73b0\u91cc\uff0c\u6bcf\u5404\u72b6\u6001\u662f\u4e00\u4e2a\u65b9\u6cd5\uff0c\u6bcf 50ms \u6267\u884c\u4e00\u6b21\uff0c\u63a5\u53d7\u53c2\u6570\uff08\u4f8b\u5982 LLM \u7684\u8f93\u51fa\uff09\u505a\u903b\u8f91\u5224\u65ad\uff0c\u901a\u8fc7\u8fd4\u56de\u4e0b\u4e00\u4e2a Routine \u5b9e\u73b0\u72b6\u6001\u8fc1\u79fb\u3002\u6709\u624b\u5199 coroutine \u7684\u611f\u89c9\u3002

\n

A.I-Generated Interactive Narrative Design in Ruby

\n

\u7528 AI \u751f\u6210\u6e38\u620f\u5267\u672c\uff0cdemo \u4e5f\u5f88\u6709\u8da3\uff0c\u4f46\u662f\u4e3a\u4e86\u505a\u51fa\u8fd9\u4e2a\u6548\u679c\u505a\u4e86\u597d\u591a\u5de5\u4f5c\uff0c\u90fd\u4e0d\u6b62\u662f LLM \u7684\u8303\u7574\u7684\u3002

\n

\u4f8b\u5982\u5b9e\u73b0\u4e86\u4e00\u4e2a DSL \uff08\u6700\u540e\u662f Blockly \u7684\u5f62\u5f0f\uff09\u6765\u5199\u5267\u672c\u3002\u7528 Logica \u6765\u9a8c\u8bc1 Storylet \u7684\u903b\u8f91\u6b63\u786e\u6027\uff0c\u8fd8\u80fd\u8bb2\u4e00\u9636\u903b\u8f91\uff0c\u4e8c\u9636\u903b\u8f91\u3002\u8ba9\u6211\u610f\u5916\u7684\u662f Logica \u751f\u6210 SQL \u7ed9 PG \u67e5\u8be2\u5c45\u7136\u6bd4 Prolog \u66f4\u5feb\uff0c\u539f\u56e0\u4e4b\u4e00\u662f\u51cf\u5c11\u4e86\u52a0\u8f7d\u6570\u636e\u5230 Prolog \u7684\u8fc7\u7a0b\uff0cProlog \u6709\u6ca1\u6709\u7c7b\u4f3c\u7684 image \u6216\u8005\u6570\u636e\u5e93\u7684\u6301\u4e45\u5316\u529f\u80fd\uff1f

\n

\u8fd8\u6709\u767d\u5b66:)

\n

\u6700\u540e\u89c2\u4f17\u8ba8\u8bba\u7684\u662f\u751f\u6210\u5267\u60c5\u7684\u6e38\u620f\u53ef\u80fd\u9047\u5230\u7684\u95ee\u9898\uff0c\u800c\u4e14\u771f\u7684\u6709\u5e02\u573a\u5417\uff1f

\n" }, { "author": { "url": "member/coool", "name": "coool", "avatar": "https://cdn.v2ex.com/gravatar/dd999e8cb14d94112f57c94fb5654906?s=73&d=retro" }, "url": "t/1087235", "title": "\u6709\u5bf9 Ruby \u611f\u5174\u8da3\u7684\u5417\uff1f", "id": "t/1087235", "date_published": "2024-11-06T12:53:45+00:00", "content_html": "

\u4e2d\u6587\u751a\u81f3\u5df2\u7ecf\u5f88\u96be\u627e\u5230\u5173\u4e8e Rails 6 \u7684\u6587\u7ae0\u6216\u4e66\u7c4d\u4e86\uff0c\u82f1\u6587\u8d44\u6599\u5374\u5c42\u51fa\u4e0d\u7a77\uff1a

\n\n

\u7531\u4e8e\u4e00\u76f4\u5bf9 Ruby \u5f88\u611f\u5174\u8da3\uff0c\u4e0a\u9762\u7684\u4e66\u57fa\u672c\u4e0a\u90fd\u770b\u4e86\u4e00\u904d\u4ee5\u4e0a\uff0c\u611f\u89c9\u5b66\u5230\u4e86\u5f88\u591a\u77e5\u8bc6\uff0c\u4f46\u5374\u6ca1\u6709\u505a\u51fa\u4ec0\u4e48\u5e94\u7528 \uff08\u4e3b\u8981\u8fd8\u662f\u53d7\u9650\u4e8e\u60f3\u6cd5\u3001\u8bbe\u8ba1\u7b49\u80fd\u529b\uff09\uff0c\u4e8e\u662f\u60f3\u7740\u4e0d\u59a8\u628a\u5b66\u5230\u7684\u77e5\u8bc6\u603b\u7ed3\u51fa\u6765\uff0c\u4e00\u65b9\u9762\u662f\u4e3a\u4e86\u81ea\u5df1\u5de9\u56fa\uff0c\u53e6\u4e00\u65b9\u9762\u4e5f\u5e0c\u671b\u80fd\u5bf9 Ruby \u611f\u5174\u8da3\u7684\u65b0\u4eba\u6709\u6240\u5e2e\u52a9\uff0c\u6240\u4ee5\u521b\u5efa\u4e86\u4e00\u4e2a Ruby \u6280\u672f\u516c\u4f17\u53f7 \u201cRuby \u672d\u8bb0\u201d\uff0c\u53d1\u4e86\u7b2c\u4e00\u7bc7\u6587\u7ae0 Rails \u5982\u4f55\u5904\u7406\u9759\u6001\u8d44\u6e90\u3002

\n

\u5728 Ruby China \u4e5f\u53d1\u4e86\u4e00\u7bc7\u5e16\u5b50.

\n" }, { "author": { "url": "member/Mark24", "name": "Mark24", "avatar": "https://cdn.v2ex.com/avatar/edea/c9b0/62847_large.png?m=1723538556" }, "url": "t/1053200", "title": "MRuby Devkit \u4e00\u4e2a\u7b80\u5355\u7684\u811a\u624b\u67b6\uff0c\u5e2e\u52a9\u4f60\u50cf Go \u4e00\u6837\u628a Ruby \u7f16\u8bd1\u6210\u53ef\u6267\u884c\u4e8c\u8fdb\u5236\u6587\u4ef6", "id": "t/1053200", "date_published": "2024-06-27T13:06:25+00:00", "content_html": "

\u9879\u76ee\u5730\u5740\uff1a https://github.com/Mark24Code/mruby-devkit

\n

MRuby Devkit \u662f\u4e00\u4e2a\u5f00\u7bb1\u5373\u7528\u7684\u811a\u624b\u67b6\u3002 \u57fa\u4e8e MRuby \u5c06\u4f60\u7684 Ruby \u4ee3\u7801\u6253\u5305\u6210 \u4e8c\u8fdb\u5236\u53ef\u6267\u884c\u6587\u4ef6\u3002

\n

\u65b9\u4fbf\u5f00\u53d1\u7c7b\u4f3c\u4e8e Golang \u7684\u4e8c\u8fdb\u5236\u53ef\u6267\u884c\u6587\u4ef6\u3002

\n
\n

\u2014\u2014 \u7075\u611f\u6765\u81ea\u4e8e Golang \u53ef\u4ee5\u7f16\u8bd1\u4e3a\u4e8c\u8fdb\u5236\u53ef\u6267\u884c\u6587\u4ef6\u7684\u8ff7\u4eba\u7279\u6027\u3002

\n
\n

\u63a5\u53d7\u7b80\u5355\u7684\u7ea6\u5b9a\uff0c\u4e13\u6ce8\u4e8e\u7f16\u5199 Ruby \u4ee3\u7801\u3002\u8f7b\u677e\u5730 build \u6210\u4e8c\u8fdb\u5236\u53ef\u6267\u884c\u6587\u4ef6\u3002

\n

\u4f7f\u7528\u8bbe\u8ba1

\n

0. \u7f16\u5199\u7a0b\u5e8f

\n

src \u4e0b\u7f16\u5199 ruby \u7a0b\u5e8f

\n

1. \u8fd0\u884c\u7a0b\u5e8f

\n
\n

\u6a21\u4eff golang \u7684 go run

\n
\n

rake run

\n

2. \u7f16\u8bd1\u5f53\u524d\u7a0b\u5e8f\uff08\u9ed8\u8ba4\u4f7f\u7528\u5f53\u524d\u8ba1\u7b97\u673a\u5e73\u53f0\uff09

\n
\n

\u6a21\u4eff golang \u7684 go build

\n
\n

rake build

\n

3.\u4ea4\u53c9\u7f16\u8bd1\u7684\u5305

\n

\u501f\u52a9 Github Action \u7f16\u8bd1\u4e0d\u540c\u5e73\u53f0\u7684\u53ef\u6267\u884c\u4e8c\u8fdb\u5236\u6587\u4ef6\u3002

\n\n

\u66f4\u591a\u8bf7\u67e5\u770b https://github.com/Mark24Code/mruby-devkit

\n" }, { "author": { "url": "member/Mark24", "name": "Mark24", "avatar": "https://cdn.v2ex.com/avatar/edea/c9b0/62847_large.png?m=1723538556" }, "url": "t/1044459", "title": "\u4f7f\u7528 Ruby-build \u5728 MacOS \u4e0a \u7f16\u8bd1 Portable Ruby", "id": "t/1044459", "date_published": "2024-05-27T11:56:40+00:00", "content_html": "

RubyChina \u8ba8\u8bba\uff1a https://ruby-china.org/topics/43710

\n

\u6211\u7684 Blog

\n

\u5927\u5bb6\u597d\uff0c\u6211\u662f Mark24 \u3002

\n

\u5206\u4eab\u4e0b\u6211\u7684\u7b14\u8bb0\uff0c\u4f7f\u7528 Ruby-build \u5728 MacOS \u4e0a \u7f16\u8bd1 Portable ruby

\n

\u8bbe\u60f3\u4e00\u4e0b\uff0c\u5982\u679c ruby \u53ef\u4ee5\u53d8\u6210 portable \u7684\uff0c\u653e\u5728 U \u76d8\u4e0a\u5c31\u53ef\u4ee5\u5e26\u8d70\uff0c\u4f20\u8f93\u5230\u4efb\u4f55\u4e00\u53f0\u7535\u8111\u4e0a\u5c31\u53ef\u4ee5\u6267\u884c\u3002

\n

Portable Ruby + \u4f60\u7684 Ruby \u4ee3\u7801 \u7684 zip \u5305\uff0c\u5c31\u50cf\u4e00\u4e2a\u884c\u8d70\u7684\u72ec\u7acb\u8f6f\u4ef6\u3002\u5c31\u50cf Go \u6253\u5305\u7684\u4e00\u6837\u3002

\n

\u4f60\u8fd8\u53ef\u4ee5\u628a\u4ed6\u4eec\u585e\u5165 \u4e00\u4e9b\u58f3\u8f6f\u4ef6\u91cc\u3002\u5c31\u50cf Electron \u90a3\u6837\u8fd0\u884c\uff08\u5185\u90e8\u662f\u4e2a\u6d4f\u89c8\u5668\uff09\u3002

\n

\u5f53\u7136 Ruby \u793e\u533a\u66fe\u7ecf\u6709\u5f88\u591a\u65b9\u6848 Traveling Ruby \u3001Ruby Packer \uff0c \u90fd\u7528\u5404\u81ea\u7684\u65b9\u5f0f\u5b9e\u73b0\u7c7b\u4f3c\u7684\u6548\u679c\uff0c\u4e0d\u8fc7\u90fd\u4e0d\u7ef4\u62a4\u4e86\u3002

\n

\u4e0b\u9762\u7528\u4e00\u4e2a\u7b80\u5355\u7684\u65b9\u6cd5\u6765\u5236\u4f5c Portable Ruby \u3002

\n
\n

\u622a\u6b62 2024-05-27 \u6700\u65b0\u7248\u672c\u662f 3.3.1 \u3002\n\u6bcf\u4e2a\u7248\u672c\u56e0\u4e3a\u7279\u6027\u7684\u4e0d\u540c\u6784\u5efa\u662f\u4e00\u4e2a\u52a8\u6001\u7684\u8fc7\u7a0b\u3002\u5c31\u4ee5 3.3.1 \u4e3a\u4f8b\u3002

\n

\u8fc7\u7a0b\u5077\u61d2\uff0c\u5efa\u7acb\u5728 ruby-build( https://github.com/rbenv/ruby-build) \u7684\u57fa\u7840\u4e0a\u3002

\n

\u4e0d\u8bba\u662f asdf \u3001rvm \u2026\u2026 \u4ed6\u4eec\u7684\u80cc\u540e\u90fd\u662f ruby-build \u4e00\u4e2a\u65b9\u4fbf\u5b89\u88c5\u7684 standalone \u7684\u5de5\u5177\u3002ruby-build \u89e3\u51b3\u4e86\u5927\u90e8\u5206\u7684\u95ee\u9898\uff0c\u6211\u4eec\u53ea\u9700\u8981\u627e\u5230\u5408\u9002\u7684\u6784\u5efa\u53c2\u6570\u3002

\n

\u4e00\u3001\u524d\u7f6e\u4f9d\u8d56

\n

1.\u5b89\u88c5 Mac \u7684\u57fa\u7840\u5de5\u5177\u96c6

\n

\u7ec8\u7aef\u8f93\u5165 xcode-select --install

\n

2.\u5b89\u88c5\u4e0a homebrew

\n

https://brew.sh/

\n

\u83b7\u5f97 \u7c7b\u4f3c\u4e8e Linux \u4e0a\u7684\u5305\u7ba1\u7406\u5de5\u5177

\n

3.\u5b89\u88c5 Ruby \u7f16\u8bd1\u9700\u8981\u7684\u524d\u7f6e\u4f9d\u8d56

\n
# \u5b89\u88c5\u524d\u7f6e\u4f9d\u8d56\n# ruby-build \u662f\u5b89\u88c5\u5de5\u5177\n# openssl@3 readline libyaml gmp \u662f\u5fc5\u8981\u7684\u4f9d\u8d56\n# rust \u662f YJIT \u5fc5\u8981\u7684\u4f9d\u8d56\uff0c\u4e0d\u88c5\u5c31\u4e0d\u4f1a\u6784\u5efa YJIT \u529f\u80fd\n\nbrew install ruby-build openssl@3 readline libyaml gmp rust\n
\n

\u4e8c\u3001\u7f16\u8bd1

\n

0.\u77e5\u8bc6\u70b9

\n
C \u8bed\u8a00\uff08 CRuby \u662f C \u8bed\u8a00\u9879\u76ee\uff09\u7f16\u8bd1\u4e00\u822c\u5206\u4e3a 3 \u4e2a\u57fa\u672c\u8fc7\u7a0b\n\n1 \uff09\u9884\u5904\u7406\uff1a\u5904\u7406\u4e00\u4e9b\u524d\u7f6e\u7684\u5b8f\u66ff\u6362\n2 \uff09\u7f16\u8bd1\uff1a\u628a .c \u4ee3\u7801\u6587\u4ef6\u7ffb\u8bd1\u6210 .o \u673a\u5668\u7801\u6587\u4ef6\u76ee\u6807\u6587\u4ef6\n3 \uff09\u94fe\u63a5\uff1a\u628a .o \u6587\u4ef6\u548c\u7cfb\u7edf\u7684\u5e95\u5c42\u5e93\uff08\u6bd4\u5982\u6807\u51c6\u8f93\u5165\u8f93\u51fa\uff09\u6b63\u786e\u7684\u5173\u8054\u8d77\u6765\u3002\u751f\u6210\u53ef\u6267\u884c\u6587\u4ef6\n\n\u94fe\u63a5\u8fd9\u90e8\uff0c\u6709\u4e24\u4e2a\u57fa\u672c\u7684\u5b9e\u73b0\n\n1 \uff09\u9759\u6001\u94fe\u63a5\n2 \uff09\u52a8\u6001\u94fe\u63a5\n\n\u9759\u6001\u94fe\u63a5\u6bd4\u8f83\u7b80\u5355\uff0c\u5c31\u662f\u628a\u6240\u6709\u7528\u5230\u7684\u4ee3\u7801\u6253\u5305\u6210\u4e00\u4e2a\u6574\u4f53\u3002\u8f6f\u4ef6\u5c31\u50cf\u4e00\u4e2a exe \u6587\u4ef6\uff0c\u5e26\u5230\u54ea\u513f\u90fd\u53ef\u4ee5\u6267\u884c\u3002\n\u4f18\u70b9\u5c31\u662f\uff0c\u968f\u5904\u6267\u884c\u3002\u7f3a\u70b9\u5c31\u662f\u4f53\u79ef\u5927\uff0c\u66f4\u65b0\u56f0\u96be\uff0c\u6bd4\u5982\u4f60\u4f9d\u8d56\u7684\u7cfb\u7edf\u90e8\u5206\u6709\u5b89\u5168\u7f3a\u9677\u3002\u4f60\u5fc5\u987b\u6574\u4f53\u66ff\u6362\u3002\n\n\u52a8\u6001\u94fe\u63a5\uff0c\u5c31\u662f\u8f6f\u4ef6\u628a\u7528\u5230\u516c\u5171\u90e8\u5206\uff08\u7cfb\u7edf\u3001\u4e0a\u6e38 lib \uff09\u7684\u90e8\u5206\uff0c\u6307\u4ed6\u4eec\u7684\u52a8\u6001\u5e93\uff08 linux \u662f so \u6587\u4ef6\uff0cwindows \u662f dll \u6587\u4ef6\uff0cmac \u91cc\u662f dylib \u6587\u4ef6\uff09\u3002\n\u4f18\u70b9\uff1a\u4f53\u79ef\u5c0f\uff0c \u5982\u679c\u516c\u5171\u90e8\u5206\u6709\u5b89\u5168\u6f0f\u6d1e\uff0c\u7cfb\u7edf\u66f4\u65b0\uff0c\u53ea\u9700\u8981\u66f4\u65b0\u52a8\u6001\u94fe\u63a5\u5e93\u6587\u4ef6\uff0c\u6240\u6709\u5f15\u7528\u7684\u8f6f\u4ef6\u90fd\u4f1a\u83b7\u5f97\u66f4\u65b0\u3002\n\u7f3a\u70b9\uff1a\u9664\u4e86\u65e0\u6cd5 portable \uff0c\u8f6f\u4ef6\u8fd0\u884c\u7684\u524d\u63d0\u662f\u7cfb\u7edf\u62e5\u6709\u76f8\u5e94\u7684 \u5e93\u3002\n\n\u52a8\u6001\u94fe\u63a5\u662f\u5e38\u6001\uff0c\u4e0d\u8bba\u662f Linux \u3001MacOS \u3001Windows \u3002\u52a8\u6001\u94fe\u63a5\u7684\u5b9e\u8df5\u8fd9\u4e48\u591a\u5e74\u8fd0\u884c\u7684\u4e00\u76f4\u5f88\u597d\u3002\u901a\u5e38\u5e93\u90fd\u662f\u6309\u7167\u52a8\u6001\u94fe\u63a5\u5e93\u65b9\u5411\u6765\u8bbe\u8ba1\u7684\u3002\u6ca1\u6709\u63d0\u4f9b\u9759\u6001\u5e93\u3002\n\nMacOS \u8fd8\u7981\u6b62\u7cfb\u7edf\u52a8\u6001\u5e93\u8fdb\u884c \u9759\u6001\u94fe\u63a5\u3002\n
\n
    \n
  1. \u6700\u7b80\u5355\u7684\u7f16\u8bd1
  2. \n
\n

\u5173\u952e\u53c2\u6570\uff1a

\n\n
RUBY_CONFIGURE_OPTS=\"--enable-load-relative --with-static-linked-ext\" ruby-build 3.2.2 $HOME/portable-ruby\n
\n

2.\u4e00\u4e9b\u4f18\u5316\u9009\u9879

\n

\u53ef\u4ee5\u53c2\u8003 https://github.com/rbenv/ruby-build

\n

\u989d\u5916\u7684\u9009\u9879

\n\n
RUBY_CONFIGURE_OPTS=\"--enable-load-relative --with-static-linked-ext --with-out-ext=win32,win32ole --disable-install-doc --disable-install-rdoc --disable-dependency-tracking \" ruby-build 3.2.2 $HOME/portable-ruby\n
\n

ruby-build \u80fd\u505a\u7684\u66f4\u591a\uff0c\u6bd4\u5982\u652f\u6301\u4ea4\u53c9\u7f16\u8bd1

\n

\u4e09\u3001Portable Ruby

\n

\u7f16\u8bd1\u6b63\u786e\u5b8c\u6210\uff0c\u4f60\u5e94\u8be5\u83b7\u5f97\u4e86 portable ruby

\n

\u5728\u62e5\u6709 \u4f9d\u8d56\u5e93\u7684\u7535\u8111\u4e0a\uff08\u5bf9\uff0c\u6211\u4eec\u524d\u9762\u89e3\u91ca\u4e86\uff0c\u7cfb\u7edf\u90e8\u5206\u662f\u7981\u6b62 \u9759\u6001\u94fe\u63a5\u7684\uff09\u3002

\n

\u4f60\u7684\u53ef\u4ee5\u628a\u4f60\u7684 ruby \u4ee3\u7801 + portable ruby \u653e\u5728\u4e00\u4e2a\u6587\u4ef6\u5939\u91cc\u3002 \u7528 \u4e00\u4e2a shell \u811a\u672c\uff0c\u901a\u8fc7\u76f8\u5bf9\u8def\u5f84\u8fde\u63a5\u8d77\u6765\u6267\u884c\u3002

\n

\u6bd4\u5982\u8fd9\u6837

\n
#!/usr/bin/env bash\n./portable-ruby/bin/ruby ./main.rb\n
\n

\u67d0\u79cd\u610f\u4e49\u4e0a\uff0cPortable Ruby + Ruby Script \u548c Go \u3001Crystal \u6253\u5305\u7684\u53ef\u6267\u884c\u6587\u4ef6\uff0c\u662f\u4e00\u6837\u7684\u3002\u5c31\u662f\u5927\u4e86\u4e00\u70b9 :D

\n

\u6211\u7684 Blog

\n" }, { "author": { "url": "member/Mark24", "name": "Mark24", "avatar": "https://cdn.v2ex.com/avatar/edea/c9b0/62847_large.png?m=1723538556" }, "url": "t/981372", "title": "[\u7ffb\u8bd1] Async Ruby\uff08\u5f02\u6b65 Ruby\uff09", "id": "t/981372", "date_published": "2023-10-12T08:21:26+00:00", "content_html": "\n

Ruby \u5df2\u7ecf\u6709\u4e86\u5f02\u6b65\u5b9e\u73b0\uff01

\n

\u5b83\u73b0\u5728\u5c31\u53ef\u4f7f\u7528\uff0c\u5df2\u7ecf\u505a\u597d\u4e86\u6295\u5165\u751f\u4ea7\u7684\u51c6\u5907\uff0c\u800c\u4e14\u5b83\u53ef\u80fd\u662f\u8fc7\u53bb\u5341\u5e74\u751a\u81f3\u66f4\u4e45\u65f6\u95f4\u91cc Ruby \u53d1\u751f\u7684\u6700\u4ee4\u4eba\u632f\u594b\u7684\u4e8b\u60c5\u3002

\n

Async Ruby \u7ed9\u8fd9\u95e8\u8bed\u8a00\u6dfb\u52a0\u4e86\u65b0\u7684\u5e76\u53d1\u7279\u6027\uff1b\u4f60\u53ef\u4ee5\u5c06\u5176\u89c6\u4e3a\u201c\u6ca1\u6709\u4efb\u4f55\u7f3a\u70b9\u7684\u7ebf\u7a0b\u201d\u3002\u5b83\u5df2\u7ecf\u5728\u915d\u917f\u4e86\u51e0\u5e74\uff0c\u4e5f\u7ec8\n\u4e8e\u5728 Ruby 3.0 \u4e2d\u51c6\u5907\u597d\u8fdb\u5165\u4e3b\u6d41\u3002

\n

\u5728\u8fd9\u7bc7\u6587\u7ae0\u4e2d\uff0c\u6211\u5e0c\u671b\u5411\u4f60\u5c55\u793a\u5f02\u6b65 Ruby \u7684\u6240\u6709\u529b\u91cf\u3001\u53ef\u6269\u5c55\u6027\u548c\u9b54\u529b\u3002\u5982\u679c\u4f60\u70ed\u7231 Ruby \uff0c\u90a3\u8fd9\u5e94\u8be5\u4f1a\u8ba9\u4f60\u975e\u5e38\u6fc0\u52a8\uff01

\n

Async gem

\n

\u4ec0\u4e48\u662f Async Ruby \uff1f

\n

\u9996\u5148\uff0cAsync \u53ea\u662f\u4e00\u4e2a gem\uff0c\u53ef\u4ee5\u901a\u8fc7 gem install async \u8fdb\u884c\u5b89\u88c5\u3002\u8fd9\u662f\u4e00\u4e2a\u76f8\u5f53\u7279\u6b8a\u7684 gem \uff0c\u56e0\u4e3a Matz( Ruby \u7684\u521b\u59cb\u4eba) \u8bf7\u5b83\u52a0\u5165 Ruby \u7684\u6807\u51c6\u5e93\uff0c\u4f46\u9080\u8bf7\u8fd8\u672a\u88ab\u63a5\u53d7\u3002

\n

Async Ruby \u662f\u7531 Samuel Williams \u521b\u5efa\u7684\uff0c\u4ed6\u4e5f\u662f\u4e00\u4e2a Ruby \u6838\u5fc3\u8d21\u732e\u8005\u3002Samuel \u8fd8\u5b9e\u73b0\u4e86 Fiber Scheduler \uff08\u7ea4\u7a0b\u8c03\u5ea6\u5668\uff09\uff0c\u8fd9\u662f Ruby 3.0 \u7684\u4e00\u4e2a\u91cd\u8981\u7279\u6027\u3002\u5b83\u662f\"\u5e93\u65e0\u5173\u7684\"\uff0c\u672a\u6765\u53ef\u80fd\u6709\u5176\u4ed6\u7528\u9014\uff0c\u4f46\u76ee\u524d\uff0c\u7ea4\u7a0b\u8c03\u5ea6\u5668\u7684\u4e3b\u8981\u76ee\u7684\u662f\u4f7f async gem \u4e0e Ruby \u65e0\u7f1d\u96c6\u6210\u3002

\n

\u5e76\u4e0d\u662f\u5f88\u591a gem \u80fd\u5f97\u5230\u4ed6\u4eec\u81ea\u5b9a\u4e49\u7684 Ruby \u96c6\u6210\uff0c\u4f46\u8fd9\u4e2a\u662f\u503c\u5f97\u7684\uff01

\n

\u6240\u6709\u8fd9\u4e9b\u90fd\u544a\u8bc9\u4f60\uff0casync \u4e0d\u662f\"\u53ea\u662f\u5916\u9762\u7684\u53e6\u4e00\u4e2a gem\"\u3002Ruby \u6838\u5fc3\u56e2\u961f\uff0c\u5305\u62ec Matz \u672c\u4eba\uff0c\u90fd\u5728\u652f\u6301\u8fd9\u4e2a gem \uff0c\u5e0c\u671b\u5b83\u80fd\u6210\u529f\u3002

\n

Async \u751f\u6001

\n

Async \u8fd8\u662f\u4e00\u4e2a gem \u751f\u6001\u7cfb\u7edf\uff0c\u8fd9\u4e9b gem \u80fd\u5f88\u597d\u5730\u4e00\u8d77\u5de5\u4f5c\u3002\u4ee5\u4e0b\u662f\u4e00\u4e9b\u6700\u6709\u7528\u7684\u4f8b\u5b50\uff1a

\n\n

\u867d\u7136\u4e0a\u9762\u5217\u51fa\u7684\u6bcf\u4e00\u4e2a gem \u90fd\u63d0\u4f9b\u4e86\u4e00\u4e9b\u6709\u7528\u7684\u4e1c\u897f\uff0c\u4f46\u4e8b\u5b9e\u662f\u4f60\u53ea\u9700\u8981\u6838\u5fc3 async gem \u5c31\u53ef\u4ee5\u83b7\u53d6\u5b83\u7684\u5927\u90e8\u5206\u597d\u5904\u3002

\n

\u5f02\u6b65\u6a21\u578b\uff08 Asynchronous paradigm \uff09

\n

Asynchronous programming \uff08\u5f02\u6b65\u7f16\u7a0b\uff09\uff0c\uff08\u5728\u4efb\u4f55\u8bed\u8a00\u4e2d\uff0c\u5305\u62ec Ruby \uff09\u5141\u8bb8\u540c\u65f6\u8fd0\u884c\u8bb8\u591a\u4e8b\u60c5\u3002\u8fd9\u6700\u5e38\u89c1\u7684\u662f\u591a\u4e2a\u7f51\u7edc I/O \u64cd\u4f5c\uff08\u5982 HTTP \u8bf7\u6c42\uff09\uff0c\u56e0\u4e3a\u5728\u8fd9\u65b9\u9762 async \u662f\u6700\u6709\u6548\u7684\u3002

\n

\u591a\u4efb\u52a1\u64cd\u4f5c\u7ecf\u5e38\u5e26\u6765\u6df7\u4e71\uff1a\u201c\u56de\u8c03\u5730\u72f1\uff08 callback hell \uff09\u201d\uff0c\u201cPromise hell \uff08 Promise \u5730\u72f1\uff09\u201d\uff0c\u4e43\u81f3 \"async-await hell \uff08 async-await \u5730\u72f1\uff09\" \u662f\u5176\u4ed6\u8bed\u8a00\u4e2d async \u63a5\u53e3\u7684\u4f17\u6240\u5468\u77e5\u7684\u7f3a\u70b9\u3002

\n

\u4f46 Ruby \u662f\u4e0d\u540c\u7684\u3002\u7531\u4e8e\u5176\u8d85\u7fa4\u7684\u8bbe\u8ba1\uff0cAsync Ruby \u4e0d\u53d7\u4efb\u4f55\u8fd9\u4e9b *-\u5730\u72f1\u7684\u56f0\u6270\u3002\u5b83\u5141\u8bb8\u7f16\u5199\u51fa\u4ee4\u4eba\u60ca\u559c\u7684\u5e72\u51c0\u3001\u7b80\u5355\u4e14\u6709\u5e8f\u7684\u4ee3\u7801\u3002\u5b83\u662f\u4e00\u4e2a\u50cf Ruby \u4e00\u6837\u4f18\u96c5\u7684 async \u5b9e\u73b0\u3002

\n

\u6ce8\u610f\uff1aAsync \u4e0d\u80fd\u7ed5\u8fc7 Ruby \u7684\u5168\u5c40\u89e3\u91ca\u5668\u9501\uff08 GIL \uff09\u3002

\n
\n

\u8bd1\u8005\u6ce8\uff1a

\n\n
\n

\u540c\u6b65\u793a\u4f8b\uff08 Synchronous example \uff09

\n

\u8ba9\u6211\u4eec\u4ece\u4e00\u4e2a\u7b80\u5355\u7684\u4f8b\u5b50\u5f00\u59cb\uff1a

\n
require \"open-uri\"\n\nstart = Time.now\n\nURI.open(\"https://httpbin.org/delay/1.6\")\nURI.open(\"https://httpbin.org/delay/1.6\")\n\nputs \"Duration: #{Time.now - start}\"\n
\n

\u4e0a\u8ff0\u4ee3\u7801\u6b63\u5728\u53d1\u8d77\u4e24\u4e2a HTTP \u8bf7\u6c42\u3002\u5355\u4e2a HTTP \u8bf7\u6c42\u7684\u603b\u6301\u7eed\u65f6\u95f4\u4e3a 2 \u79d2\uff0c\u5305\u62ec\uff1a

\n\n

\u8ba9\u6211\u4eec\u8fd0\u884c\u8fd9\u4e2a\u793a\u4f8b\uff1a

\n

\u6301\u7eed\u65f6\u95f4\uff1a4.010390391

\n

\u5982\u9884\u671f\uff0c\u7a0b\u5e8f\u9700\u8981 2 x 2 \u79d2 = 4 \u79d2\u624d\u80fd\u5b8c\u6210\u3002

\n

\u8fd9\u6bb5\u4ee3\u7801\u8fd8\u4e0d\u9519\uff0c\u4f46\u5b83\u8fd0\u884c\u901f\u5ea6\u6162\u3002\u5bf9\u4e8e\u8fd9\u4e24\u4e2a\u8bf7\u6c42\uff0c\u6267\u884c\u8fc7\u7a0b\u5927\u6982\u50cf\u8fd9\u6837\uff1a

\n\n

\u95ee\u9898\u5728\u4e8e\u7a0b\u5e8f\u5728\u5927\u90e8\u5206\u65f6\u95f4\u91cc\u90fd\u5904\u4e8e\u7b49\u5f85\u72b6\u6001\uff1b 2 \u79d2\u949f\uff08\u5bf9\u4e8e\u8ba1\u7b97\u673a\uff09\u5c31\u50cf\u6c38\u6052\u3002

\n

Threads \uff08\u7ebf\u7a0b\uff09

\n

\u63d0\u9ad8\u591a\u4e2a\u7f51\u7edc\u8bf7\u6c42\u901f\u5ea6\u7684\u5e38\u7528\u65b9\u6cd5\u662f\u4f7f\u7528\u7ebf\u7a0b\u3002\u4ee5\u4e0b\u662f\u4e00\u4e2a\u793a\u4f8b\uff1a

\n
require \"open-uri\"\n\n@counter = 0\n\nstart = Time.now\n\n1.upto(2).map {\n Thread.new do\n URI.open(\"https://httpbin.org/delay/1.6\")\n\n @counter += 1\n end\n}.each(&:join)\n\nputs \"Duration: #{Time.now - start}\"\n
\n

\u4ee3\u7801\u7684\u8f93\u51fa\u662f\uff1a

\n

\u6301\u7eed\u65f6\u95f4: 2.055751087

\n

\u6211\u4eec\u5c06\u6267\u884c\u65f6\u95f4\u7f29\u77ed\u5230 2 \u79d2\u949f\uff0c\u8fd9\u8868\u660e\u8bf7\u6c42\u5728\u540c\u65f6\u8fd0\u884c\u3002\u90a3\u4e48\uff0c\u95ee\u9898\u89e3\u51b3\u4e86\u5417\uff1f

\n

\u597d\u5427\uff0c\u522b\u8fc7\u4e8e\u7740\u6025\uff1a\u5982\u679c\u4f60\u505a\u8fc7\u4efb\u4f55\u771f\u5b9e\u4e16\u754c\u7684\u7ebf\u7a0b\u7f16\u7a0b\uff0c\u4f60\u4f1a\u77e5\u9053\u7ebf\u7a0b\u5f88\u96be\u3002\u771f\u7684\uff0c\u975e\u5e38\u96be\u3002

\n

\u5982\u679c\u4f60\u6253\u7b97\u505a\u4efb\u4f55\u4e25\u8083\u7684\u7ebf\u7a0b\u5de5\u4f5c\uff0c\u4f60\u6700\u597d\u4e60\u60ef\u4f7f\u7528\u4e92\u65a5\uff08 mutexes \uff09\uff0c\u6761\u4ef6\u53d8\u91cf\uff08 condition variables \uff09\uff0c\u5904\u7406\u8bed\u8a00\u7ea7\u7684\u7ade\u6001\u6761\u4ef6\uff08 race conditions \uff09...\u751a\u81f3\u6211\u4eec\u7684\u7b80\u5355\u793a\u4f8b\u5728 @counter += 1 \u8fd9\u4e00\u884c\u5c31\u6709\u4e00\u4e2a\u7ade\u6001\u6761\u4ef6\u9519\u8bef\uff01

\n

\u7ebf\u7a0b\u662f\u56f0\u96be\u7684\uff0c\u5e76\u4e14\u6beb\u65e0\u7591\u95ee\u4e0b\u9762\u7684\u58f0\u660e\u5728 Ruby \u793e\u533a\u4e00\u76f4\u88ab\u4e0d\u65ad\u63d0\u53ca\uff1a

\n
 I regret adding threads.\n\n \u2014 Matz\n
\n

Async \u4f8b\u5b50

\n

\u9274\u4e8e\u6240\u6709\u7684\u7ebf\u7a0b\u590d\u6742\u6027\uff0cRuby \u793e\u533a\u65e9\u5c31\u5e94\u8be5\u6709\u4e00\u4e2a\u66f4\u597d\u7684\u5e76\u53d1\u6a21\u5f0f\u3002\u6709\u4e86 Async Ruby \uff0c\u6211\u4eec\u7ec8\u4e8e\u6709\u4e86\u4e00\u79cd\u3002

\n

async-http

\n

\u8ba9\u6211\u4eec\u770b\u770b\u4f7f\u7528 Async Ruby \u6765\u8fdb\u884c\u4e24\u6b21 HTTP \u8bf7\u6c42\u7684\u540c\u6837\u7684\u4f8b\u5b50\uff1a

\n
require \"async\"\nrequire \"async/http/internet\"\n\nstart = Time.now\n\nAsync do |task|\n http_client = Async::HTTP::Internet.new\n\n task.async do\n http_client.get(\"https://httpbin.org/delay/1.6\")\n end\n\n task.async do\n http_client.get(\"https://httpbin.org/delay/1.6\")\n end\nend\n\nputs \"Duration: #{Time.now - start}\"\n\n
\n

\u793a\u4f8b\u7684\u8f93\u51fa\u662f\uff1a

\n

\u6301\u7eed\u65f6\u95f4\uff1a1.996420725

\n

\u770b\u770b\u603b\u8fd0\u884c\u65f6\u95f4\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u51fa\u8bf7\u6c42\u662f\u540c\u65f6\u8fd0\u884c\u7684\u3002

\n

\u8fd9\u4e2a\u4f8b\u5b50\u663e\u793a\u4e86 Async Ruby \u7a0b\u5e8f\u7684\u4e00\u822c\u7ed3\u6784\uff1a

\n\n

\u4e00\u65e6\u4f60\u4e60\u60ef\u4e86\uff0c\u4f60\u4f1a\u53d1\u73b0\u8fd9\u4e2a\u7ed3\u6784\u5b9e\u9645\u4e0a\u975e\u5e38\u6574\u6d01\u3002

\n

URI.open

\n

\u524d\u4e00\u4e2a\u4f8b\u5b50\u4e2d\u53ef\u4ee5\u88ab\u8ba4\u4e3a\u662f\u4e00\u4e2a\u7f3a\u70b9\u7684\u4e8b\u60c5\u662f\uff0c\u5b83\u4f7f\u7528\u4e86 async-http\uff0c\u4e00\u4e2a\u5177\u6709\u5f02\u6b65\u7279\u6027\u7684 HTTP \u5ba2\u6237\u7aef\u3002\u6211\u4eec\u5927\u591a\u6570\u4eba\u6709\u81ea\u5df1\u559c\u6b22\u7684 Ruby HTTP \u5ba2\u6237\u7aef\uff0c\u6211\u4eec\u4e0d\u60f3\u518d\u82b1\u65f6\u95f4\u53bb\u5b66\u4e60\u53e6\u4e00\u4e2a HTTP \u5e93\u7684\u8be6\u7ec6\u60c5\u51b5\u3002\n\u8ba9\u6211\u4eec\u770b\u6536\u540c\u6837\u7684\u4f8b\u5b50\uff0c\u53ea\u662f\u8fd9\u6b21\u4f7f\u7528 URI.open\uff1a

\n
require \"async\"\nrequire \"open-uri\"\n\nstart = Time.now\n\nAsync do |task|\n task.async do\n URI.open(\"https://httpbin.org/delay/1.6\")\n end\n\n task.async do\n URI.open(\"https://httpbin.org/delay/1.6\")\n end\nend\n\nputs \"Duration: #{Time.now - start}\"\n
\n

\u4e0e\u524d\u4e00\u4e2a\u4f8b\u5b50\u7684\u552f\u4e00\u533a\u522b\u662f\uff0c\u6211\u4eec\u7528 Ruby \u7684\u6807\u51c6\u5e93\u4e2d\u7684\u65b9\u6cd5 URI.open \u66ff\u6362\u4e86 async-http\u3002

\n

\u793a\u4f8b\u7684\u8f93\u51fa\u662f\uff1a

\n

\u6301\u7eed\u65f6\u95f4\uff1a2.030451785

\n

\u8fd9\u4e2a\u6301\u7eed\u65f6\u95f4\u663e\u793a\u4e86\u4e24\u4e2a\u8bf7\u6c42\u662f\u5e76\u884c\u8fd0\u884c\u7684\uff0c\u6240\u4ee5\u6211\u4eec\u8ba4\u4e3a URI.open \u662f\u5f02\u6b65\u8fd0\u884c\u7684\uff01

\n

\u8fd9\u4e00\u5207\u771f\u7684\u5f88\u597d\u3002\u6211\u4eec\u4e0d\u4ec5\u4e0d\u9700\u8981\u5fcd\u53d7\u7ebf\u7a0b\u53ca\u5176\u590d\u6742\u6027\uff0c\u800c\u4e14\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 Ruby \u7684\u6807\u51c6 URI.open \u6765\u8fd0\u884c\u8bf7\u6c42\uff0c

\n

\u65e0\u8bba\u662f\u5728 Async \u5757\u7684\u5916\u90e8\u8fd8\u662f\u5185\u90e8\u3002\u8fd9\u65e0\u7591\u53ef\u4ee5\u4e3a\u6211\u4eec\u63d0\u4f9b\u4e00\u4e9b\u65b9\u4fbf\u7684\u4ee3\u7801\u91cd\u7528\u3002

\n

\u5176\u4ed6 HTTP clients

\n

\u867d\u7136 URI.open \u662f\u666e\u901a\u7684 Ruby \uff0c\u4f46\u53ef\u80fd\u5e76\u4e0d\u662f\u4f60\u559c\u6b22\u7684\u8fdb\u884c HTTP \u8bf7\u6c42\u7684\u65b9\u5f0f\u3002\u800c\u4e14\uff0c\u4f60\u4e5f\u4e0d\u7ecf\u5e38\u770b\u5230\u5b83\u88ab\u7528\u4e8e\"serious work(\u6b63\u5f0f\u7684\u5de5\u4f5c)\"\u3002

\n

\u4f60\u53ef\u80fd\u6709\u4f60\u81ea\u5df1\u559c\u6b22\u7684 HTTP gem \uff0c\u4f60\u53ef\u80fd\u4f1a\u95ee \"\u5b83\u80fd\u5728 Async \u4e2d\u5de5\u4f5c\u5417\"\uff1f\u4e3a\u4e86\u627e\u51fa\u7b54\u6848\uff0c\u8fd9\u91cc\u6709\u4e00\u4e2a\u4f7f\u7528 HTTParty\uff08\u4e00\u79cd\u77e5\u540d\u7684 HTTP \u5ba2\u6237\u7aef\uff09\u7684\u4f8b\u5b50\u3002

\n
require \"async\"\nrequire \"open-uri\"\nrequire \"httparty\"\n\nstart = Time.now\n\nAsync do |task|\n task.async do\n URI.open(\"https://httpbin.org/delay/1.6\")\n end\n\n task.async do\n HTTParty.get(\"https://httpbin.org/delay/1.6\")\n end\nend\n\nputs \"Duration: #{Time.now - start}\"\n
\n

\u5728\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u6211\u4eec\u5728\u4e00\u8d77\u8fd0\u884c\u4e86 URI.open \u548c HTTParty\uff0c\u8fd9\u5b8c\u5168\u6ca1\u95ee\u9898\u3002

\n

\u8f93\u51fa\u662f\uff1a

\n

\u6301\u7eed\u65f6\u95f4\uff1a2.010069566

\n

\u5b83\u8fd0\u884c\u7684\u65f6\u95f4\u7a0d\u5fae\u8d85\u8fc7\u4e86 2 \u79d2\uff0c\u8fd9\u8868\u660e\u4e24\u4e2a\u8bf7\u6c42\u662f\u5e76\u53d1\u8fd0\u884c\u7684\uff08\u540c\u65f6\u8fdb\u884c\uff09\u3002\n\u8fd9\u91cc\u7684\u8981\u70b9\u662f\uff1a\u4f60\u53ef\u4ee5\u5728\u4e00\u4e2a Async \u4e0a\u4e0b\u6587\u4e2d\u8fd0\u884c\u4efb\u4f55 HTTP \u5ba2\u6237\u7aef\uff0c\u5b83\u5c06\u4f1a\u5f02\u6b65\u8fd0\u884c\u3002Async Ruby \u5b8c\u5168\u652f\u6301\u4efb\u4f55\u73b0\u6709\u7684 HTTP gem \uff01

\n

\u9ad8\u7ea7\u4f8b\u5b50

\n

\u5230\u76ee\u524d\u4e3a\u6b62\uff0c\u6211\u4eec\u53ea\u770b\u5230 Async Ruby \u7528\u5404\u79cd HTTP \u5ba2\u6237\u7aef\u8fdb\u884c\u8bf7\u6c42\u3002\u8ba9\u6211\u4eec\u63ed\u793a Async \u5728 Ruby 3 \u4e2d\u7684\u5168\u90e8\u80fd\u529b\u3002

\n
require \"async\"\nrequire \"open-uri\"\nrequire \"httparty\"\nrequire \"redis\"\nrequire \"net/ssh\"\nrequire \"sequel\"\n\nDB = Sequel.postgres\nSequel.extension(:fiber_concurrency)\nstart = Time.now\n\nAsync do |task|\n task.async do\n URI.open(\"https://httpbin.org/delay/1.6\")\n end\n\n task.async do\n HTTParty.get(\"https://httpbin.org/delay/1.6\")\n end\n\n task.async do\n Redis.new.blpop(\"abc123\", 2)\n end\n\n task.async do\n Net::SSH.start(\"164.90.237.21\").exec!(\"sleep 1\")\n end\n\n task.async do\n DB.run(\"SELECT pg_sleep(2)\")\n end\n\n task.async do\n sleep 2\n end\n\n task.async do\n `sleep 2`\n end\nend\n\nputs \"Duration: #{Time.now - start}\"\n
\n

\u6211\u4eec\u6269\u5c55\u4e86\u5305\u542b URI.open \u548c HTTParty \u7684\u524d\u4e00\u4e2a\u4f8b\u5b50\uff0c\u589e\u52a0\u4e86\u4e94\u4e2a\u9644\u52a0\u64cd\u4f5c\uff1a

\n\n

\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\u7684\u6240\u6709\u64cd\u4f5c\u4e5f\u9700\u8981\u6070\u597d 2 \u79d2\u624d\u80fd\u8fd0\u884c\u3002

\n

\u4ee5\u4e0b\u662f\u793a\u4f8b\u8f93\u51fa\uff1a

\n

\u6301\u7eed\u65f6\u95f4\uff1a2.083171146

\n

\u6211\u4eec\u5f97\u5230\u7684\u8f93\u51fa\u7ed3\u679c\u548c\u4e4b\u524d\u4e00\u6837\uff0c\u8fd9\u8868\u660e\u6240\u6709\u7684\u64cd\u4f5c\u90fd\u662f\u5e76\u53d1\u8fd0\u884c\u7684\u3002\u54c7\uff0c\u8fd9\u6709\u5f88\u591a\u4e0d\u540c\u7684 gem \u53ef\u4ee5\u5f02\u6b65\u8fd0\u884c\uff01

\n

\u91cd\u70b9\uff1a\u4efb\u4f55\u963b\u585e\u64cd\u4f5c\uff08 Ruby \u89e3\u91ca\u5668\u7b49\u5f85\u7684\u65b9\u6cd5\uff09\u90fd\u4e0e Async \u517c\u5bb9\uff0c\u5e76\u5c06\u5728 Ruby 3.0 \u548c\u66f4\u9ad8\u7248\u672c\u7684 Async \u4ee3\u7801\u5757\u4e2d\u5f02\u6b65\u5de5\u4f5c\u3002

\n

\u6027\u80fd\u770b\u8d77\u6765\u5f88\u597d\uff1a7 x 2 = 14 \u79d2\uff0c\u4f46\u793a\u4f8b\u5728 2 \u79d2\u5185\u5b8c\u6210 \u2013 \u5f88\u5bb9\u6613\u5f97\u5230 7 \u500d\u7684\u63d0\u5347\u3002

\n

Fiber Scheduler \uff08\u7ea4\u7a0b\u8c03\u5ea6\u5668\uff09

\n

\u8ba9\u6211\u4eec\u82b1\u4e00\u70b9\u65f6\u95f4\u6765\u53cd\u601d\u4e00\u4e9b\u91cd\u8981\u7684\u4e8b\u60c5\u3002\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\u7684\u6240\u6709\u64cd\u4f5c\uff08\u4f8b\u5982\uff0cURI.open \uff0cRedis \uff0csleep \uff09\u90fd\u4f1a\u6839\u636e\u4e0a\u4e0b\u6587\u7684\u4e0d\u540c\u800c\u8868\u73b0\u4e0d\u540c\uff1a

\n\n

\u4f46\u662f\uff0c\u4f8b\u5982\uff0cHTTParty \u6216 sleep \u65b9\u6cd5\u5982\u4f55\u80fd\u540c\u6b65\u548c\u5f02\u6b65\u540c\u65f6\u5b58\u5728\u5462\uff1f Async \u5e93\u662f\u5426\u5bf9\u6240\u6709\u8fd9\u4e9b gems \u548c\u5185\u90e8 Ruby \u65b9\u6cd5\u8fdb\u884c\u4e86\u7334\u5b50\u8865\u4e01\uff1f\n\u8fd9\u79cd\u9b54\u672f\u662f\u7531\u4e8e Fiber Scheduler\u3002\u8fd9\u662f Ruby 3.0 \u7684\u4e00\u4e2a\u7279\u6027\uff0c\u4f7f\u5f97 async \u80fd\u591f\u5f88\u597d\u5730\u4e0e\u73b0\u6709\u7684 Ruby gems \u548c\u65b9\u6cd5\u96c6\u6210 - \u4e0d\u9700\u8981\u4efb\u4f55 hack \u6216 \u7334\u5b50\u8865\u4e01(Monkey patch) \uff01

\n

Fiber Scheduler \u4e5f\u53ef\u4ee5\u5355\u72ec\u4f7f\u7528 (\u94fe\u63a5\u8bd1\u6587)\uff01\u7528\u8fd9\u79cd\u65b9\u5f0f\uff0c\u53ea\u9700\u8981\u51e0\u4e2a\u5185\u7f6e\u7684 Ruby \u65b9\u6cd5\u5c31\u80fd\u542f\u7528\u5f02\u6b65\u7f16\u7a0b\u3002

\n

\u5982\u4f60\u6240\u60f3\uff0cFiber Scheduler \u89e6\u53ca\u7684\u4ee3\u7801\u8303\u56f4\u975e\u5e38\u5e7f\uff1a\u5b83\u662f Ruby \u5f53\u524d\u6240\u6709\u7684\u963b\u585e API \uff01\u8fd9\u7edd\u4e0d\u4ec5\u4ec5\u662f\u4e00\u4e2a\u5c0f\u529f\u80fd\u3002

\n

\u6269\u5c55\u4f8b\u5b50

\n

\u8ba9\u6211\u4eec\u63d0\u9ad8\u6548\u7387\uff0c\u5e76\u5c55\u793a\u4e00\u4e2a Async Ruby \u64c5\u957f\u7684\u53e6\u4e00\u65b9\u9762\uff1a\u6269\u5c55(scaling)\u3002

\n
require \"async\"\nrequire \"async/http/internet\"\nrequire \"redis\"\nrequire \"sequel\"\n\nDB = Sequel.postgres(max_connections: 1000)\nSequel.extension(:fiber_concurrency)\n# Warming up redis clients\nredis_clients = 1.upto(1000).map { Redis.new.tap(&:ping) }\n\nstart = Time.now\n\nAsync do |task|\n http_client = Async::HTTP::Internet.new\n\n 1000.times do |i|\n task.async do\n http_client.get(\"https://httpbin.org/delay/1.6\")\n end\n\n task.async do\n redis_clients[i].blpop(\"abc123\", 2)\n end\n\n task.async do\n DB.run(\"SELECT pg_sleep(2)\")\n end\n\n task.async do\n sleep 2\n end\n\n task.async do\n `sleep 2`\n end\n end\nend\n\nputs \"Duration: #{Time.now - start}s\"\n
\n

\u6b64\u4f8b\u5b50\u57fa\u4e8e\u4e4b\u524d\u7684\u90a3\u4e2a\u4f8b\u5b50\uff0c\u53ea\u662f\u505a\u4e86\u4e00\u4e9b\u6539\u52a8\uff1a

\n\n

\u5c31\u50cf\u4e4b\u524d\u4e00\u6837\uff0c\u6bcf\u4e2a\u72ec\u7acb\u64cd\u4f5c\u90fd\u9700\u8981 2 \u79d2\u624d\u80fd\u6267\u884c\u3002\u5176\u8f93\u51fa\u4e3a\uff1a

\n

\u6301\u7eed\u65f6\u95f4: 13.672289712

\n

\u8fd9\u8868\u660e\u7d2f\u79ef\u8fd0\u884c\u65f6\u95f4\u4e3a 10,000 \u79d2\u7684 5,000 \u4e2a\u64cd\u4f5c\u4ec5\u5728 13.6 \u79d2\u5185\u5c31\u5b8c\u6210\u4e86\uff01

\n

\u8fd9\u4e2a\u6301\u7eed\u65f6\u95f4\u6bd4\u524d\u9762\u7684\u4f8b\u5b50\uff08 2 \u79d2\uff09\u8981\u957f\uff0c\u8fd9\u662f\u56e0\u4e3a\u521b\u5efa\u8fd9\u4e48\u591a\u7f51\u7edc\u8fde\u63a5\u7684\u5f00\u9500\u3002

\n

\u6211\u4eec\u51e0\u4e4e\u6ca1\u6709\u8fdb\u884c\u6027\u80fd\u8c03\u4f18\uff08\u4f8b\u5982\uff0c\u8c03\u6574\u5783\u573e\u6536\u96c6\uff0c\u5185\u5b58\u5206\u914d\u7b49\uff09\uff0c\u4f46\u6211\u4eec\u4ecd\u7136\u5b9e\u73b0\u4e86 730 \u500d\u7684\u201c\u52a0\u901f\u201d\uff0c\u5728\u6211\u770b\u6765\uff0c\u8fd9\u662f\u4e00\u4e2a\u76f8\u5f53\u4ee4\u4eba\u5370\u8c61\u6df1\u523b\u7684\u7ed3\u679c\uff01

\n

\u6269\u5bb9\u9650\u5236(Scaling limits)

\n

\u6700\u597d\u7684\u90e8\u5206\u662f\uff1a\u6211\u4eec\u53ea\u662f\u521d\u6b65\u63a2\u7d22\u4e86\u4f7f\u7528 Async Ruby \u6240\u80fd\u505a\u5230\u7684\u4e8b\u60c5\u3002

\n

\u867d\u7136\u7ebf\u7a0b\uff08 Threads \uff09\u7684\u6700\u5927\u6570\u91cf\u662f 2048 \uff08\u81f3\u5c11\u5728\u6211\u7684\u673a\u5668\u4e0a\u662f\u8fd9\u6837\uff09\uff0c\u4f46\u662f Async tasks \u7684\u4e0a\u9650\u6570\u91cf\u662f\u767e\u4e07\u7ea7\u522b\u7684\uff01

\n

\u4f60\u771f\u7684\u53ef\u4ee5\u540c\u65f6\u8fd0\u884c\u767e\u4e07\u4e2a\u5f02\u6b65\u64cd\u4f5c\u5417\uff1f\u662f\u7684\uff0c\u4f60\u53ef\u4ee5 - \u5df2\u7ecf\u6709\u4e9b\u7528\u6237\u505a\u5230\u4e86\u3002

\n

Async \u771f\u7684\u4e3a Ruby \u6253\u5f00\u4e86\u65b0\u5c40\u9762\uff1a\u60f3\u8c61\u4e00\u4e0b\u4e00\u4e2a HTTP \u670d\u52a1\u5668\u5904\u7406\u6210\u5343\u4e0a\u4e07\u7684\u5ba2\u6237\uff0c\u6216\u8005\u540c\u4e00\u65f6\u95f4\u5904\u7406\u6210\u767e\u4e0a\u5343\u7684 websocket \u8fde\u63a5 ... \u8fd9\u90fd\u662f\u53ef\u80fd\u7684\uff01

\n

\u7ed3\u8bba

\n

Async Ruby \u7ecf\u8fc7\u4e86\u6f2b\u957f\u800c\u795e\u79d8\u7684\u5f00\u53d1\u671f\uff0c\u4f46\u73b0\u5728\u5b83\u7a33\u5b9a\u4e14\u5df2\u7ecf\u51c6\u5907\u597d\u6295\u5165\u751f\u4ea7\u3002\u5df2\u7ecf\u6709\u4e00\u4e9b\u516c\u53f8\u5728\u751f\u4ea7\u73af\u5883\u4e0b\u8fd0\u884c\u5b83\u5e76\u4ece\u4e2d\u53d7\u76ca\u3002\u8981\u5f00\u59cb\u4f7f\u7528\u5b83\uff0c\u4f60\u53ef\u4ee5\u53bb Async \u7684\u4ed3\u5e93\u770b\u770b\u3002

\n

\u552f\u4e00\u7684\u6ce8\u610f\u70b9\u662f\uff0c\u5b83\u4e0d\u80fd\u548c Ruby on Rails \u4e00\u8d77\u5de5\u4f5c\uff0c\u56e0\u4e3a ActiveRecord \u4e0d\u652f\u6301 Async gem \u3002\u4f46\u5982\u679c\u4e0d\u6d89\u53ca\u5230 ActiveRecord\uff0c\u4f60\u4ecd\u7136\u53ef\u4ee5\u5728 Rails \u4e2d\u4f7f\u7528\u5b83\u3002

\n

Async \u7684\u6700\u5927\u4f18\u52bf\u5728\u4e8e\u6269\u5c55\u7f51\u7edc I/O \u64cd\u4f5c\uff0c\u6bd4\u5982\u8fdb\u884c\u6216\u63a5\u6536 HTTP \u8bf7\u6c42\u3002\u5bf9\u4e8e CPU \u5bc6\u96c6\u578b\u7684\u5de5\u4f5c\u8d1f\u8f7d\uff0c\u7ebf\u7a0b\u662f\u66f4\u597d\u7684\u9009\u62e9\uff0c\u4f46\u81f3\u5c11\u6211\u4eec\u4e0d\u518d\u9700\u8981\u628a\u4ed6\u4eec\u7528\u4e8e\u6240\u6709\u4e8b\u60c5\u3002

\n

Async Ruby \u975e\u5e38\u5f3a\u5927\uff0c\u53ef\u6269\u5c55\u6027\u6781\u9ad8\u3002\u5b83\u662f\u4e00\u4e2a\u6e38\u620f\u89c4\u5219\u6539\u53d8\u8005\uff0c\u6211\u5e0c\u671b\u8fd9\u7bc7\u6587\u7ae0\u80fd\u8bc1\u660e\u8fd9\u4e00\u70b9\u3002Async \u6539\u53d8\u4e86 Ruby \u7684\u53ef\u80fd\u6027\uff0c\u5e76\u4e14\u5f53\u6211\u4eec\u6240\u6709\u4eba\u5f00\u59cb\u66f4\u591a\u5730\u201c\u5f02\u6b65\u201d\u601d\u8003\u65f6\uff0c\u5b83\u5c06\u5bf9 Ruby \u793e\u533a\u4ea7\u751f\u91cd\u5927\u5f71\u54cd\u3002

\n

\u6700\u597d\u7684\u4e00\u70b9\u662f\uff0c\u5b83\u4e0d\u4f1a\u4f7f\u4efb\u4f55\u73b0\u6709\u7684\u4ee3\u7801\u53d8\u5f97\u8fc7\u65f6\u3002\u5c31\u50cf Ruby \u672c\u8eab\u4e00\u6837\uff0cAsync \u8bbe\u8ba1\u5f97\u5f88\u7f8e\uff0c\u4f7f\u7528\u8d77\u6765\u4e5f\u5f88\u6109\u5feb\u3002

\n

\u5e0c\u671b\u4f60\u5728\u4f7f\u7528 Async Ruby \u65f6\u7f16\u7a0b\u6109\u5feb\uff01

\n

Happy hacking with Async Ruby!

\n" }, { "author": { "url": "member/Mark24", "name": "Mark24", "avatar": "https://cdn.v2ex.com/avatar/edea/c9b0/62847_large.png?m=1723538556" }, "url": "t/981356", "title": "[\u7ffb\u8bd1] Ruby Fiber Scheduler", "id": "t/981356", "date_published": "2023-10-12T07:46:08+00:00", "content_html": "\n

Fiber Scheduler(\u7ea4\u7a0b\u8c03\u5ea6\u5668)\u5728 Ruby \u4e2d\u5b9e\u73b0\u5f02\u6b65\u7f16\u7a0b\u3002\u8be5\u529f\u80fd\u662f Ruby 3.0 \u7684\u4e00\u5927\u589e\u5f3a\u529f\u80fd\uff0c\u5e76\u4e14\u4e5f\u662f\u4f18\u79c0\u7684 async gem \u7684\u6838\u5fc3\u7ec4\u4ef6\u4e4b\u4e00\u3002\n\u6700\u68d2\u7684\u4e00\u70b9\u662f\uff0c\u4f60\u5e76\u4e0d\u9700\u8981\u4e00\u4e2a\u5b8c\u6574\u7684\u6846\u67b6\u5c31\u80fd\u5f00\u59cb\uff01\u53ea\u9700\u4f7f\u7528\u4e00\u5bf9\u5185\u7f6e\u7684 Ruby \u65b9\u6cd5\uff0c\u5c31\u80fd\u72ec\u7acb\u5730\u5b9e\u73b0\u7ea4\u7a0b\u8c03\u5ea6\u5668\u5e76\u4eab\u53d7\u5230\u5f02\u6b65\u7f16\u7a0b\u7684\u597d\u5904\u3002

\n

\u7ea4\u7a0b\u8c03\u5ea6\u5668\u4e3b\u8981\u5305\u62ec\u4e24\u90e8\u5206\uff1a

\n\n

\u975e\u5e38\u611f\u8c22 Samuel Williams \uff01\u4ed6\u662f Ruby \u7684\u6838\u5fc3\u5f00\u53d1\u8005\uff0c\u8bbe\u8ba1\u5e76\u5b9e\u73b0\u4e86\u7ea4\u7a0b\u8c03\u5ea6\u5668\u8fd9\u4e00\u529f\u80fd\u5e76\u6574\u5408\u5230\u4e86\u8bed\u8a00\u4e2d\u3002

\n

Fiber Scheduler interface \uff08\u7ea4\u7a0b\u8c03\u5ea6\u5668\u63a5\u53e3\uff09

\n

Fiber Scheduler \uff08\u7ea4\u7a0b\u8c03\u5ea6\u5668\uff09\u63a5\u53e3\u662f\u4e00\u5957\u963b\u585e\u64cd\u4f5c\u7684\u94a9\u5b50\uff0c\u5b83\u5141\u8bb8\u5728\u963b\u585e\u64cd\u4f5c\u53d1\u751f\u65f6\u63d2\u5165\u5f02\u6b65\u884c\u4e3a\u3002\u5b83\u50cf\u662f\u5e26\u6709\u53cd\u8f6c\u7684\u56de\u8c03\uff1a\u5f53\u5f02\u6b65\u56de\u8c03\u88ab\u6267\u884c\u65f6\uff0c\u4e3b\u963b\u585e\u65b9\u6cd5\u4e0d\u4f1a\u8fd0\u884c\u3002\n\u8fd9\u4e9b\u94a9\u5b50\u5728 Fiber::SchedulerInterface \u7c7b\u4e2d\u6709\u6587\u6863\u8bb0\u5f55\u3002\u8fd9\u4e2a Ruby \u529f\u80fd\u80cc\u540e\u7684\u4e00\u4e9b\u4e3b\u8981\u601d\u60f3\u5305\u62ec\uff1a

\n\n

Hook implementation (\u94a9\u5b50\u5b9e\u73b0)

\n

\u8ba9\u6211\u4eec\u770b\u4e00\u4e2a\u793a\u4f8b\uff0c\u663e\u793a\u5982\u4f55\u5b9e\u73b0 Kernel#sleep \u94a9\u5b50\u3002\u5728\u5b9e\u8df5\u4e2d\uff0c\u6240\u6709\u7684\u94a9\u5b50\u90fd\u662f\u7528 C \u8bed\u8a00\u7f16\u5199\u7684\uff0c\u4f46\u4e3a\u4e86\u6e05\u6670\u8d77\u89c1\uff0c\u8fd9\u91cc\u4f7f\u7528\u4e86 Ruby \u4f2a\u4ee3\u7801\u3002

\n
module Kernel\n def sleep(duration = nil)\n if Fiber.scheduler\n Fiber.scheduler.kernel_sleep(duration)\n else\n synchronous_sleep(duration)\n end\n end\nend\n
\n

\u4ee5\u4e0a\u4ee3\u7801\u7684\u9605\u8bfb\u65b9\u5f0f\u5982\u4e0b\uff1a

\n\n

\u5176\u4ed6\u7684\u94a9\u5b50\u7684\u5de5\u4f5c\u65b9\u5f0f\u4e5f\u7c7b\u4f3c\u3002

\n

Blocking operations \uff08\u963b\u585e\u64cd\u4f5c\uff09

\n

\u5df2\u7ecf\u591a\u6b21\u63d0\u5230\u4e86\"Blocking operations \uff08\u963b\u585e\u64cd\u4f5c\uff09\"\u8fd9\u4e2a\u6982\u5ff5\uff0c\u4f46\u5b83\u5230\u5e95\u662f\u4ec0\u4e48\u610f\u601d\u5462\uff1f\u963b\u585e\u64cd\u4f5c\u662f\u6307\u4efb\u4f55 Ruby \u8fdb\u7a0b\uff08\u66f4\u5177\u4f53\u5730\u8bf4\uff1a\u5f53\u524d\u7ebf\u7a0b\uff09\u6700\u7ec8\u4f1a\u7b49\u5f85\u7684\u64cd\u4f5c\u3002\u4e00\u4e2a\u66f4\u5177\u63cf\u8ff0\u6027\u7684\u540d\u79f0\u662f\u201cwaiting operations \uff08\u7b49\u5f85\u64cd\u4f5c\uff09\u201d\u3002\n\u4e00\u4e9b\u4f8b\u5b50\u5982\u4e0b\uff1a

\n\n

\u4f5c\u4e3a\u4e00\u4e2a\u53cd\u4f8b\uff0c\u4ee5\u4e0b\u4ee3\u7801\u7247\u6bb5\u9700\u8981\u4e00\u6bb5\u65f6\u95f4\u624d\u80fd\u5b8c\u6210\uff0c\u4f46\u4e0d\u5305\u542b\u963b\u585e\u64cd\u4f5c\uff1a

\n
def fibonacci(n)\n return n if [0, 1].include? n\n\n fibonacci(n - 1) + fibonacci(n - 2)\nend\n\nfibonacci(100)\n
\n

\u83b7\u53d6 fibonacci(100) \u7684\u7ed3\u679c\u9700\u8981\u7b49\u5f85\u5f88\u957f\u65f6\u95f4\uff0c\u4f46\u53ea\u6709\u7a0b\u5e8f\u5458\u5728\u7b49\u5f85\uff01\u6574\u4e2a\u65f6\u95f4 Ruby \u89e3\u91ca\u5668\u90fd\u5728\u5de5\u4f5c\uff0c\u540e\u53f0\u8fdb\u884c\u8ba1\u7b97\u3002\u4e00\u4e2a\u7b80\u5355\u7684\u6590\u6ce2\u90a3\u5951\u5b9e\u73b0\u5e76\u4e0d\u5305\u542b\u963b\u585e\u64cd\u4f5c\u3002

\n

\u53d1\u5c55\u5bf9\u963b\u585e\u64cd\u4f5c\u662f\u4ec0\u4e48\uff08\u548c\u4e0d\u662f\u4ec0\u4e48\uff09\u7684\u76f4\u89c9\u662f\u503c\u5f97\u7684\uff0c\u56e0\u4e3a\u5f02\u6b65\u7f16\u7a0b\u7684\u6574\u4e2a\u76ee\u6807\u5c31\u662f\u540c\u65f6\u7b49\u5f85\u591a\u4e2a\u963b\u585e\u64cd\u4f5c\u3002

\n

Fiber Scheduler implementation \uff08\u7ea4\u7a0b\u8c03\u5ea6\u5668\u5b9e\u73b0\uff09

\n

\u7ea4\u7a0b\u8c03\u5ea6\u5668\u5b9e\u73b0\u662f Fiber Scheduler \u529f\u80fd\u7684\u7b2c\u4e8c\u5927\u90e8\u5206\u3002

\n

\u5982\u679c\u4f60\u60f3\u5728 Ruby \u4e2d\u542f\u7528\u5f02\u6b65\u884c\u4e3a\uff0c\u4f60\u9700\u8981\u4e3a\u5f53\u524d\u7ebf\u7a0b\u8bbe\u7f6e\u4e00\u4e2a Fiber Scheduler \u5bf9\u8c61\u3002\u8fd9\u662f\u901a\u8fc7 Fiber.set_scheduler(scheduler) \u65b9\u6cd5\u5b8c\u6210\u7684\u3002\u5b9e\u73b0\u901a\u5e38\u662f\u4e00\u4e2a\u5b9a\u4e49\u4e86\u6240\u6709 Fiber::SchedulerInterface \u65b9\u6cd5\u7684\u7c7b\u3002

\n

Ruby \u4e0d\u63d0\u4f9b\u9ed8\u8ba4\u7684 Fiber Scheduler \u7c7b\uff0c\u4e5f\u6ca1\u6709\u53ef\u4ee5\u7528\u4e8e\u6b64\u76ee\u7684\u7684\u5bf9\u8c61\u3002\u8fd9\u770b\u8d77\u6765\u4e0d\u5bfb\u5e38\uff0c\u4f46\u5b9e\u9645\u4e0a\u4e0d\u5c06 Fiber Scheduler \u5b9e\u73b0\u5305\u542b\u5728\u8bed\u8a00\u4e2d\u662f\u4e00\u4e2a\u597d\u7684\u957f\u671f\u51b3\u5b9a\u3002\u6700\u597d\u5c06\u8fd9\u79cd\u76f8\u5bf9\u5feb\u901f\u6f14\u53d8\u7684\u5173\u6ce8\u70b9\u7559\u5728 Ruby \u6838\u5fc3\u4e4b\u5916\u3002\n\u4ece\u5934\u5f00\u59cb\u7f16\u5199 Fiber Scheduler \u7c7b\u662f\u4e00\u9879\u590d\u6742\u7684\u4efb\u52a1\uff0c\u6240\u4ee5\u6700\u597d\u4f7f\u7528\u73b0\u6709\u7684\u89e3\u51b3\u65b9\u6848\u3002\u5b9e\u73b0\u7684\u5217\u8868\uff0c\u5b83\u4eec\u7684\u4e3b\u8981\u533a\u522b\u548c\u63a8\u8350\u53ef\u4ee5\u5728 Fiber Scheduler List \u9879\u76ee\u4e2d\u627e\u5230\u3002

\n

\u4e3e\u4e2a\u4f8b\u5b50

\n

\u8ba9\u6211\u4eec\u6765\u770b\u770b\u4ec5\u4f7f\u7528 Fiber Scheduler \u53ef\u4ee5\u505a\u4ec0\u4e48\u3002\n\u6240\u6709\u793a\u4f8b\u90fd\u4f7f\u7528 Ruby 3.1 \u548c\u6765\u81ea fiber_scheduler gem \u7684 FiberScheduler \u7c7b\uff0c\u8fd9\u4e2a gem \u7531\u6211\u7ef4\u62a4\u3002\u8fd9\u4e2a gem \u5bf9\u4e8e\u793a\u4f8b\u6765\u8bf4\u4e0d\u662f\u4e00\u4e2a\u786c\u6027\u4f9d\u8d56\u9879\uff0c\u56e0\u4e3a\u5982\u679c\u5c06\u4ee5\u4e0b\u4ee3\u7801\u7247\u6bb5\u4e2d\u7684 FiberScheduler \u66ff\u6362\u4e3a\u53e6\u4e00\u4e2a Fiber Scheduler \u7c7b\uff0c\u6bcf\u4e2a\u4ee3\u7801\u7247\u6bb5\u4ecd\u7136\u5e94\u8be5\u53ef\u4ee5\u5de5\u4f5c\u3002

\n

\u57fa\u672c\u793a\u4f8b

\n

\u8fd9\u91cc\u6709\u4e00\u4e2a\u7b80\u5355\u7684\u793a\u4f8b\uff1a

\n
require \"fiber_scheduler\"\nrequire \"open-uri\"\n\nFiber.set_scheduler(FiberScheduler.new)\n\nFiber.schedule do\n URI.open(\"https://httpbin.org/delay/2\")\nend\n\nFiber.schedule do\n URI.open(\"https://httpbin.org/delay/2\")\nend\n
\n

\u4e0a\u9762\u7684\u4ee3\u7801\u521b\u5efa\u4e86\u4e24\u4e2a\u7ea4\u7a0b\uff0c\u6bcf\u4e2a\u7ea4\u7a0b\u90fd\u8fdb\u884c\u4e00\u6b21 HTTP \u8bf7\u6c42\u3002\u8fd9\u4e9b\u8bf7\u6c42\u5e76\u884c\u8fd0\u884c\uff0c\u6574\u4e2a\u7a0b\u5e8f\u5728 2 \u79d2\u5185\u5b8c\u6210\u3002

\n\n

\u8fd9\u4e2a\u793a\u4f8b\u4ec5\u4f7f\u7528\u4e86\u6807\u51c6\u7684 Ruby \u65b9\u6cd5 - Fiber.set_scheduler \u548c Fiber.schedule \u81ea Ruby 3.0 \u7248\u672c\u4ee5\u6765\u5c31\u4e00\u76f4\u53ef\u7528\u3002

\n

\u9ad8\u7ea7\u4f8b\u5b50

\n

\u6211\u4eec\u6765\u770b\u770b\u8fd0\u884c\u591a\u79cd\u4e0d\u540c\u64cd\u4f5c\u662f\u4ec0\u4e48\u6837\u5b50\u7684\uff1a

\n
require \"fiber_scheduler\"\nrequire \"httparty\"\nrequire \"open-uri\"\nrequire \"redis\"\nrequire \"sequel\"\n\nDB = Sequel.postgres\nSequel.extension(:fiber_concurrency)\n\nFiber.set_scheduler(FiberScheduler.new)\n\nFiber.schedule do\n URI.open(\"https://httpbin.org/delay/2\")\nend\n\nFiber.schedule do\n # Use any HTTP library\n HTTParty.get(\"https://httpbin.org/delay/2\")\nend\n\nFiber.schedule do\n # Works with any TCP protocol library\n Redis.new.blpop(\"abc123\", 2)\nend\n\nFiber.schedule do\n # Make database queries\n DB.run(\"SELECT pg_sleep(2)\")\nend\n\nFiber.schedule do\n sleep 2\nend\n\nFiber.schedule do\n # Run system commands\n `sleep 2`\nend\n
\n

\u5982\u679c\u6211\u4eec\u987a\u5e8f\u8fd0\u884c\u8fd9\u4e2a\u7a0b\u5e8f\uff0c\u5b83\u5927\u7ea6\u9700\u8981 12 \u79d2\u624d\u80fd\u5b8c\u6210\u3002\u4f46\u662f\u7531\u4e8e\u8fd9\u4e9b\u64cd\u4f5c\u662f\u5e76\u884c\u8fd0\u884c\u7684\uff0c\u6240\u4ee5\u603b\u7684\u8fd0\u884c\u65f6\u95f4\u4ec5\u4ec5\u8d85\u8fc7 2 \u79d2\u3002\n\u4f60\u5e76\u4e0d\u4ec5\u9650\u4e8e\u53d1\u8d77 HTTP \u8bf7\u6c42\u3002\u4efb\u4f55\u5185\u7f6e\u5728 Ruby \u4e2d\u6216\u7531\u5916\u90e8 gem \u5b9e\u73b0\u7684\u963b\u585e\u64cd\u4f5c\u90fd\u53ef\u4ee5\u5de5\u4f5c\uff01

\n

\u6269\u5c55\u793a\u4f8b

\n

\u8fd9\u662f\u4e00\u4e2a\u7b80\u5355\u7684\uff0c\u663e\u7136\u662f\u4eba\u4e3a\u523b\u610f\u7684\u793a\u4f8b\uff0c\u540c\u65f6\u8fd0\u884c\u4e00\u4e07\u4e2a\u64cd\u4f5c\u3002

\n
require \"fiber_scheduler\"\n\nFiber.set_scheduler(FiberScheduler.new)\n\n10_000.times do\n Fiber.schedule do\n sleep 2\n end\nend\n
\n

\u4e0a\u8ff0\u4ee3\u7801\u7684\u5b8c\u6210\u65f6\u95f4\u7565\u8d85\u8fc7 2 \u79d2\u3002

\n

\u7531\u4e8e\u5176\u4f4e\u5f00\u9500\uff0csleep \u65b9\u6cd5\u88ab\u9009\u62e9\u7528\u4e8e\u6269\u5c55\u793a\u4f8b\u3002\u5982\u679c\u6211\u4eec\u4f7f\u7528\u7f51\u7edc\u8bf7\u6c42\uff0c\u7531\u4e8e\u9700\u8981\u5efa\u7acb\u6570\u5343\u4e2a\u8fde\u63a5\u5e76\u8fdb\u884c SSL \u63e1\u624b\u7b49\uff0c\u6267\u884c\u65f6\u95f4\u5c06\u4f1a\u66f4\u957f\u3002

\n

\u5f02\u6b65\u7f16\u7a0b\u7684\u4e3b\u8981\u4f18\u52bf\u4e4b\u4e00\u662f\u80fd\u591f\u540c\u65f6\u7b49\u5f85\u8bb8\u591a\u963b\u585e\u64cd\u4f5c\u3002\u963b\u585e\u64cd\u4f5c\u6570\u91cf\u7684\u589e\u52a0\u5c06\u589e\u52a0\u8fd9\u79cd\u4f18\u52bf\u3002\u5e78\u8fd0\u7684\u662f\uff0c\u8fd0\u884c\u5927\u91cf\u534f\u7a0b(fibers)\u975e\u5e38\u7b80\u5355\u3002

\n

\u7ed3\u8bba

\n

Ruby \u53ea\u9700\u8981\u4e00\u4e2a\u7ea4\u7a0b\u8c03\u5ea6\u5668\uff08 Fiber Scheduler \uff09\u548c\u4e00\u4e9b\u5185\u7f6e\u65b9\u6cd5\u5c31\u53ef\u4ee5\u5f02\u6b65\u5de5\u4f5c - \u4e0d\u9700\u8981\u4efb\u4f55\u6846\u67b6\uff01

\n

\u4f7f\u5176\u5de5\u4f5c\u5f88\u5bb9\u6613\u3002\u9009\u62e9\u4e00\u4e2a\u7ea4\u7a0b\u8c03\u5ea6\u5668\uff08 Fiber Scheduler \uff09\u5b9e\u73b0\uff0c\u7136\u540e\u4f7f\u7528\u4ee5\u4e0b\u8fd9\u4e9b\u65b9\u6cd5\uff1a

\n\n

\u4e00\u65e6\u4f60\u5f00\u59cb\u8fd0\u884c\uff0c\u4f60\u53ef\u4ee5\u901a\u8fc7\u5c06\u5b83\u5305\u88c5\u5728\u4e00\u4e2a Fiber.schedule \u5757\u4e2d\u6765\u4f7f\u4efb\u4f55\u4ee3\u7801\u5f02\u6b65\u5316\u3002

\n
Fiber.schedule do\n SynchronousCode.run\nend\n
\n

\u6574\u4e2a\u5e93\u53ef\u4ee5\u8f7b\u677e\u5730\u4f7f\u7528\u8fd9\u79cd\u65b9\u6cd5\u8f6c\u6362\u4e3a\u5f02\u6b65\uff0c\u800c\u4e14\u5f80\u5f80\u4e0d\u9700\u8981\u6bd4\u8fd9\u91cc\u5c55\u793a\u7684\u66f4\u591a\u52aa\u529b\u3002

\n

\u5f02\u6b65\u7f16\u7a0b\u7684\u91cd\u5927\u597d\u5904\u662f\u5e76\u884c\u5316\u963b\u585e/\u7b49\u5f85\u64cd\u4f5c\u4ee5\u51cf\u5c11\u7a0b\u5e8f\u8fd0\u884c\u65f6\u95f4\u3002\u8fd9\u901a\u5e38\u610f\u5473\u7740\u5728\u5355\u4e2a CPU \u4e0a\u8fd0\u884c\u66f4\u591a\u7684\u64cd\u4f5c\uff0c\u6216\u8005\u66f4\u597d\u5730\uff0c\u5728\u4f60\u7684 Web \u670d\u52a1\u5668\u4e0a\u5904\u7406\u66f4\u591a\u7684\u8bf7\u6c42\u3002

\n

\u795d\u4f60\u4f7f\u7528\u7ea4\u7a0b\u8c03\u5ea6\u5668\uff08 Fiber Scheduler \uff09\u6109\u5feb\uff01

\n

Happy hacking with Fiber Scheduler!

\n" }, { "author": { "url": "member/Mark24", "name": "Mark24", "avatar": "https://cdn.v2ex.com/avatar/edea/c9b0/62847_large.png?m=1723538556" }, "url": "t/905233", "title": "Ruby 3.2.0 \u53d1\u5e03", "id": "t/905233", "date_published": "2022-12-28T12:56:22+00:00", "content_html": "

https://www.ruby-lang.org/en/news/2022/12/25/ruby-3-2-0-released/

\n" }, { "author": { "url": "member/Livid", "name": "Livid", "avatar": "https://cdn.v2ex.com/avatar/c4ca/4238/1_large.png?m=1776858751" }, "url": "t/902116", "title": "Ruby on Mac", "id": "t/902116", "date_published": "2022-12-13T02:28:46+00:00", "content_html": "https://www.rubyonmac.dev/

\u89e3\u51b3 Ruby \u5f00\u53d1\u73af\u5883\u5728 macOS \u4e0a\u5404\u79cd\u5b89\u88c5\u95ee\u9898\u7684\u65b9\u6848\u3002" }, { "author": { "url": "member/Mark24", "name": "Mark24", "avatar": "https://cdn.v2ex.com/avatar/edea/c9b0/62847_large.png?m=1723538556" }, "url": "t/872259", "title": "\u7528 100 \u884c Ruby \u4ee3\u7801\u6a21\u62df Javascript \u7684 Eventloop", "id": "t/872259", "date_published": "2022-08-11T11:04:15+00:00", "content_html": "

\u524d\u8a00

\n

\u5927\u5bb6\u597d\uff0c\u6211\u662f Mark24

\n\n

\u80cc\u666f

\n

\u6211\u4eec\u90fd\u77e5\u9053 Javascript \u662f\u5355\u7ebf\u7a0b\u7684\u3002

\n

\u4eca\u5929\u770b\u5230\u4e00\u4e2a\u6709\u8da3\u7684\u5e16\u5b50 www.v2ex.com/t/871848\uff0c\u4e3b\u8981\u662f\u4e89\u8bba Javascript \u7684\u4f18\u7f3a\u70b9\u3002\u6211\u770b\u5230\u8fd9\u4e2a\u8bc4\u8bba\u89c9\u5f97\u5f88\u6709\u610f\u601d\uff1a

\n
@qrobot:\n\n....\u7701\u7565....\n\n\n\u591a\u7ebf\u7a0b\u4e0b\u4f1a\u6d88\u8017\u4ee5\u4e0b\u8d44\u6e90\n\n1. \u5207\u6362\u9875\u8868\u5168\u5c40\u76ee\u5f55\n2. \u5207\u6362\u5185\u6838\u6001\u5806\u6808\n3. \u5207\u6362\u786c\u4ef6\u4e0a\u4e0b\u6587\uff08\u8fdb\u7a0b\u6062\u590d\u524d\uff0c\u5fc5\u987b\u88c5\u5165\u5bc4\u5b58\u5668\u7684\u6570\u636e\u7edf\u79f0\u4e3a\u786c\u4ef6\u4e0a\u4e0b\u6587\uff09\nip(instruction pointer)\uff1a\u6307\u5411\u5f53\u524d\u6267\u884c\u6307\u4ee4\u7684\u4e0b\u4e00\u6761\u6307\u4ee4\nbp(base pointer): \u7528\u4e8e\u5b58\u653e\u6267\u884c\u4e2d\u7684\u51fd\u6570\u5bf9\u5e94\u7684\u6808\u5e27\u7684\u6808\u5e95\u5730\u5740\nsp(stack poinger): \u7528\u4e8e\u5b58\u653e\u6267\u884c\u4e2d\u7684\u51fd\u6570\u5bf9\u5e94\u7684\u6808\u5e27\u7684\u6808\u9876\u5730\u5740\ncr3:\u9875\u76ee\u5f55\u57fa\u5740\u5bc4\u5b58\u5668\uff0c\u4fdd\u5b58\u9875\u76ee\u5f55\u8868\u7684\u7269\u7406\u5730\u5740\n......\n\n4. \u5237\u65b0 TLB\n5. \u7cfb\u7edf\u8c03\u5ea6\u5668\u7684\u4ee3\u7801\u6267\u884c\n\n....\u7701\u7565.....\n\n
\n

\u8fd9\u4f4d\u540c\u5b66\u5217\u4e3e\u4e86\u591a\u7ebf\u7a0b\u5207\u6362\u7684\u65f6\u5019\u53d1\u751f\u4e86\u4ec0\u4e48\u3002\n\u8fd9\u6837\u7ed9\u4e86\u4e00\u79cd\u5f88\u76f4\u89c2\u7684\u611f\u53d7\uff0c\u5c31\u662f\u591a\u7ebf\u7a0b\u5207\u6362\u7684\u65f6\u5019\u53d1\u751f\u4e86\u5f88\u591a\u4e8b\u60c5\uff0c\u5b9e\u9645\u4e0a\u4f1a\u6bd4\u5355\u7ebf\u7a0b\uff08\u53ea\u9700\u8981\u5207\u6362\u51fd\u6570\u4e0a\u4e0b\u6587\uff09\u8981\u6d88\u8017\u70b9\u66f4\u591a\u7684\u8d44\u6e90\u3002

\n

\u5b9e\u9645\u4e0a\u51e1\u662f\u4ea4\u4e92\u7684\u8f6f\u4ef6\uff0c\u6700\u7ec8\u90fd\u662f \u5355\u7ebf\u7a0b\u6a21\u578b + \u4e8b\u4ef6\u9a71\u52a8\u8f85\u52a9\u3002

\n

\u4ece\u719f\u6089\u7684\u6d4f\u89c8\u5668\u3001\u6e38\u620f\u3001\u5e94\u7528\u7a0b\u5e8f\u2026\u2026\u90fd\u662f\u5982\u6b64\u3002

\n

\u4e5f\u6709\u591a\u7ebf\u7a0b\u5b9e\u73b0\u7684\u3002\u8fd9\u91ccMultithreaded toolkits: A failed dream? (2004) \u6709\u5f88\u591a\u8ba8\u8bba\u3002

\n

\u5b9e\u9645\u4e0a\u5355\u7ebf\u7a0b\u6a21\u578b\u662f\u6700\u540e\u7684\u80dc\u51fa\u8005\u3002

\n

Javascript \u5185\u90e8\u5355\u7ebf\u7a0b\u5904\u7406\u4efb\u52a1\uff0c\u4e3b\u8981\u662f\u6709\u4e00\u4e2a EventLoop \u5355\u7ebf\u7a0b\u7684\u5faa\u73af\u5b9e\u73b0\u3002

\n

\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7 Javascript \u7684\u8868\u73b0\uff0c\u53cd\u63a8\u5b9e\u73b0\u4e00\u4e0b EventLoop \u3002

\n

EventLoop \u5b9e\u73b0

\n

Javascript \u7684\u884c\u4e3a

\n

\u6211\u4eec\u77e5\u9053 setTimeout \u5728 Javascript \u4e2d\u7528\u6765\u63a8\u8fdf\u4efb\u52a1\u3002\u5b9e\u9645\u4e0a\u81ea\u4ece Promise \u51fa\u73b0\u4e4b\u540e\uff0c\u6e10\u6e10\u6709\u4e24\u4e2a\u6982\u5ff5\u51fa\u73b0\u5728\u5927\u5bb6\u7684\u89c6\u91ce\u91cc\u3002

\n\n

setTimeout \u5c5e\u4e8e\u5b8f\u4efb\u52a1\uff0c\u800c promise \u7684 then \u56de\u8c03\u5c5e\u4e8e\u5fae\u4efb\u52a1\u3002

\n

\u8fd8\u6709\u4e00\u4e2a\u5c31\u662f Javascript \u5728\u7b2c\u4e00\u6b21\u540c\u6b65\u6267\u884c\u4ee3\u7801\u7684\u65f6\u5019\uff0c\u662f\u5b8f\u4efb\u52a1\u3002

\n

EventLoop \u7684\u8868\u73b0\u662f\uff0c\u9664\u4e86\u7b2c\u4e00\u6b21\u6267\u884c\u7ed3\u675f\u4e4b\u540e\uff0c\u5982\u679c\u6709\u66f4\u9ad8\u4f18\u5148\u7ea7\u7684 \u5fae\u4efb\u52a1\u603b\u662f\u5148\u6267\u884c\u5fae\u4efb\u52a1\uff0c\u7136\u540e\u518d\u6267\u884c\u5b8f\u4efb\u52a1\u3002

\n

setTimeout \u662f\u4e00\u4e2a\u5b9a\u65f6\u5668\uff0c\u5f88\u7279\u522b\u7684\u662f\u4ed6\u5728\u4f1a\u5728\u8ba1\u65f6\u5668\u7ebf\u7a0b\u5de5\u4f5c\uff0c\u8fd0\u884c\u65f6\u95f4\u4e4b\u540e\uff0c\u56de\u8c03\u51fd\u6570\u4f1a\u88ab\u63d2\u5165\u5230 \u5b8f\u4efb\u52a1\u4e2d\u6267\u884c\u3002\u8ba1\u65f6\u5668\u7ebf\u7a0b\u5176\u5b9e\u4e0d\u662f Javascript \u865a\u62df\u7684\u4e00\u90e8\u5206\uff0c\u4ed6\u662f\u6d4f\u89c8\u5668\u7684\u90e8\u5206\u3002

\n

Ruby \u6a21\u62df

\n

Javascript \u662f\u5355\u7ebf\u7a0b\u7684\u3002Ruby \u662f\u652f\u6301\u591a\u7ebf\u7a0b\u7684\u3002\u6211\u4eec\u53ef\u4ee5\u7528 Ruby \u6a21\u62df\u4e00\u4e2a \u5355\u7ebf\u7a0b\u7684\u6838\u5fc3\uff0c\u548c\u5355\u72ec\u7684\u8ba1\u65f6\u5668\u7ebf\u7a0b\uff0c\u8fd9\u90fd\u662f\u5f88\u8f7b\u677e\u7684\u4e8b\u60c5\u3002

\n

\u5176\u5b9e\u6211\u4eec\u542c\u5230\u4e86\u8fd9\u4e2a\u884c\u4e3a \u2014\u2014 \u82b1 1 \u5206\u949f\u5927\u6982\u80fd\u60f3\u5230\uff0cEventLoop \u7684\u5de5\u4f5c\u6a21\u578b

\n\n

\u6211\u4eec\u53ef\u4ee5\u7528\u6570\u7ec4\u5f53\u505a \u961f\u5217\u3002\u4f46\u662f \u7531\u4e8e\u5b58\u5728\u65f6\u95f4\u7ebf\u7a0b\uff0c\u8fd8\u5f97\u7528 Thread#Queue \u6709\u4fdd\u969c\u4e00\u70b9\u3002

\n

\u5927\u6982\u7684\u6a21\u578b\u53ef\u4ee5\u753b\u51fa\u6765\uff0c\u60f3\u8fd9\u4e2a\u6837:

\n

Eventloop Model

\n
\uff08 start)\n |\n init (e.g create TimerThread )\n |\n sync task (e.g read & run code) \n | \n |\n ------------------>\n| | -------------\n| macro_task --- add timer task --> | TimerThread |\n| (Eventloop) | <-- insertjob result --- -------------\n| |\n| micro_task\n| |\n| |\n <----------------- \n |\n |\n (end)\n\n
\n\n

\u7136\u540e\u6211\u4eec\u5927\u6982\u7528 100 \u884c\u4e0d\u5230\u5c31\u53ef\u4ee5\u5b9e\u73b0\u5982\u4e0b:

\n

\u9700\u8981\u8bf4\u660e\u7684\u662f:

\n
    \n
  1. \n

    settimeout \u4e0d\u8981\u7528\u6bcf\u4e00\u4e2a\u65b0\u7684\u7ebf\u7a0b\u6765\u6a21\u62df\uff0c\u56e0\u4e3a\u4e00\u65e6\u591a\u7ebf\u7a0b\uff0c\u6d89\u53ca\u5230\u62a2\u5360\u5f0f\u56de\u8c03\uff0c\u5176\u5b9e\u8fd4\u56de\u7684\u65f6\u95f4\u4e0d\u786e\u5b9a\u3002\u4f60\u7684\u7ed3\u679c\u662f\u4e0d\u7a33\u5b9a\u7684\u3002\n\u6211\u4eec\u9700\u8981\u5355\u72ec\u5b9e\u73b0\u4e00\u4e2a\u8ba1\u65f6\u5668\u7ebf\u7a0b\u3002

    \n
  2. \n
  3. \n

    \u6211\u4eec\u901a\u8fc7\u884c\u4e3a\u5c01\u88c5\uff0c\u628a\u4e24\u8fb9\u51fd\u6570\u5199\u6cd5\u5bf9\u7167\uff0c\u8fd9\u6837\u53ef\u4ee5\u590d\u5236

    \n
  4. \n
\n

\u8fd0\u884c\u770b\u7ed3\u679c

\n

\"result_example\"

\n

\u5177\u4f53\u5b9e\u73b0

\n
# https://github.com/Mark24Code/rb_simulate_eventloop\nrequire 'thread'\n\nclass EventLoop\n \n attr_accessor :macro_queue, :micro_queue\n def initialize\n @running = true\n \n @macro_queue = Queue.new\n @micro_queue = Queue.new\n\n @time_thr_task_queue = Queue.new\n\n @timer = Timer.new(@time_thr_task_queue, @macro_queue)\n\n # \u8ba1\u65f6\u7ebf\u7a0b\uff0c\u662f\u4e00\u4e2a\u540c\u6b65\u961f\u5217\n # \u4f1a\u628a\u5b9a\u65f6\u4efb\u52a1\u7ed3\u679c\u585e\u56de\u5b8f\u961f\u5217\n @timer_thx = Thread.new do\n @timer.run\n end\n end\n\n\n def before_loop_sync_tasks\n # do sth setting\n @first_task.call\n end\n\n def task(&block)\n # \u8fd9\u91cc\u653e\u7f6e\u7b2c\u4e00\u6b21\u540c\u6b65\u4efb\u52a1\n # \n # \u5916\u90e8\u4e66\u5199\u7684\u4ee3\u7801\uff0c\u6a21\u62df\u8bfb\u53d6 js\n # \u63d0\u4f9b\u5185\u90e8\u7684 api\n @first_task = -> () { instance_eval(&block) }\n end\n\n def after_loop\n puts \"[after_loop] eventloop is quit :D\"\n end\n\n def macro_queue_works\n while !@macro_queue.empty?\n job = @macro_queue.shift\n job.call\n end\n end\n\n def micro_queue_works\n while !@micro_queue.empty?\n job = @micro_queue.shift\n job.call\n end\n end\n\n def start\n begin\n before_loop_sync_tasks\n\n while @running\n\n macro_queue_works\n\n micro_queue_works\n\n # avoid CPU 100%\n sleep 0.1\n end\n ensure\n after_loop\n end\n end\n\n # dsl public api\n # inner api\n def macro_task(&block)\n @macro_queue.push(block)\n end\n\n def micro_task(&block)\n @micro_queue.push(block)\n end\n\n def settimeout(time, &block)\n # \u6a21\u62df\u5b9a\u65f6\u5668\u7ebf\u7a0b\n if time == 0\n time = 0.1\n end\n\n # \u65b9\u6848 1: \u7528\u72ec\u7acb\u5206\u6563\u7684\u7ebf\u7a0b\u6a21\u62df\u5b58\u5728\u95ee\u9898\n # \u62a2\u5360\u7684\u8fd4\u56de\u987a\u5e8f\u4e0d\u662f\u56fa\u5b9a\u7684\n # t = Thread.new do\n # sleep time\n # @micro_queue.push(block)\n # end\n ## !!! \u8fd9\u91cc\u4e00\u5b9a\u4e0d\u80fd\u963b\u585e\uff0c\u4e00\u65e6\u963b\u585e\u5c31\u4e0d\u662f\u5355\u7ebf\u7a0b\u6a21\u578b\n ## \u6709\u5916\u5faa\u73af\u63a7\u5236\u4e0d\u4f1a\u7ed3\u675f\n # t.join\n\n # \u65b9\u6848 2: \u65f6\u95f4\u7ebf\u7a0b\u4e5f\u9700\u8981\u5355\u72ec\u6a21\u62df\n # \u5efa\u7acb\u4e00\u4e2a\u65f6\u95f4\u4efb\u52a1\n @time_thr_task_queue.push({\n sleep_time: Time.now.to_i + time,\n job: -> () { @micro_queue.push(block) }\n })\n\n end\nend\n\nclass Timer\n def initialize(task_queue, macro_queue)\n @task_queue = task_queue\n @macro_queue = macro_queue\n end\n def run\n while (task = @task_queue.shift)\n sleep_time = task[:sleep_time]\n if sleep_time >= Time.now.to_i\n @macro_queue.push(task[:job])\n else\n @task_queue.push(task)\n end\n end\n end\nend\n
\n

\u603b\u7ed3

\n

\u9009\u62e9\u5355\u7ebf\u7a0b\u7684\u539f\u56e0\u662f\u56e0\u4e3a

\n\n

Nginx \u3001Redis \u5185\u90e8\u4e5f\u5b9e\u73b0\u4e86\u5355\u7ebf\u7a0b\u6a21\u578b\uff0c\u6765\u5e94\u5bf9\u5927\u91cf\u7684\u8bf7\u6c42\uff0c\u63d0\u9ad8\u5e76\u53d1\u3002

\n

\u73b0\u5728\u6211\u4eec\u5927\u6982\u77e5\u9053\u4e86\uff0c\u6d4f\u89c8\u5668\u3001\u5e94\u7528\u3001app \u3001\u56fe\u5f62\u754c\u9762\u3001\u6e38\u620f\u2026\u2026

\n

\u4ed6\u4eec\u7684\u80cc\u540e\u5927\u6982\u662f\u4ec0\u4e48\u6837\u5b50\u3002 \u7834\u9664\u795e\u79d8\u611f +1 :D

\n\n" }, { "author": { "url": "member/Mark24", "name": "Mark24", "avatar": "https://cdn.v2ex.com/avatar/edea/c9b0/62847_large.png?m=1723538556" }, "url": "t/868773", "title": "\u7ba1\u7aa5\u8821\u6d4b\u4ece\u601d\u8003\u6e38\u620f\u5230\u5b9e\u73b0 2048", "id": "t/868773", "date_published": "2022-07-26T05:42:29+00:00", "content_html": "

\u6211\u7684\u535a\u5ba2

\n

\u524d\u8a00

\n

\u672c\u6587\u6bd4\u8f83\u5570\u55e6\uff0c\u66f4\u503e\u5411\u4e8e\u662f\u81ea\u8a00\u81ea\u8bed\u3002\u4e0d\u8fc7\u6211\u5199\u5b8c\u56de\u987e\uff0c\u8fd9\u66f4\u50cf\u662f\u8fd9\u6bb5\u65f6\u95f4\uff0c\u81ea\u7531\u601d\u8003\u7684\u603b\u7ed3 :P

\n

\u4e0d\u8fc7\u6211\u4e0d\u662f\u6e38\u620f\u9886\u57df\u7684\u4eba\uff0c\u8fd9\u90e8\u5206\u90fd\u662f\u4e1a\u4f59\u6478\u9c7c\u601d\u8003\u7684\u8bb0\u5f55\uff0c\u5982\u679c\u6709\u52d8\u8bef\uff0c\u8bf7\u4e0e\u6211\u8054\u7cfb\uff0c\u975e\u5e38\u4e50\u610f\u4ea4\u6d41\u3002

\n

\u6587\u7ae0\u53ef\u80fd\u9700\u8981 30 \u5206\u949f\u3002

\n

\u4e3b\u8981\u6d89\u53ca\u7684\u4e3b\u9898\uff1a

\n\n

\u4f7f\u7528 Ruby \u5b9e\u73b0 demo \u3002

\n

rb2048

\n\n

\u9879\u76ee\u5b89\u88c5: gem install rb2048

\n

\u8fdb\u5165\u6e38\u620f

\n

\u5e2e\u52a9\u4fe1\u606f\uff1a rb2048 --help

\n
Usage: rb2048 [options]\n --version verison\n --size SIZE Size of board: 4-10\n --level LEVEL Hard Level 2-5\n
\n

\u5f00\u59cb\u6e38\u620f rb2048

\n
 -- Ruby 2048 --\n\n -------------------------------------\n | 16 | 16 | 2 | 16 |\n -------------------------------------\n | 0 | 0 | 0 | 0 |\n -------------------------------------\n | 0 | 0 | 0 | 2 |\n -------------------------------------\n | 0 | 0 | 0 | 0 |\n -------------------------------------\n\n Score: 16 You:UP\n\n\n\n Control: W(\u2191) A(\u2190) S(\u2193) D(\u2192) Q(quit) R(Restart)\n
\n

\u5347\u7ea7\u96be\u5ea6 rb2048 --size=10 --level=5

\n
 -- Ruby 2048 --\n\n -----------------------------------------------------------------------\n | 8 | 16 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 |\n -----------------------------------------------------------------------\n | 0 | 16 | 0 | 16 | 0 | 8 | 0 | 0 | 0 | 0 |\n -----------------------------------------------------------------------\n | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 16 | 8 |\n -----------------------------------------------------------------------\n | 0 | 16 | 0 | 8 | 0 | 0 | 0 | 0 | 0 | 2 |\n -----------------------------------------------------------------------\n | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n -----------------------------------------------------------------------\n | 0 | 8 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n -----------------------------------------------------------------------\n | 8 | 0 | 0 | 0 | 0 | 4 | 0 | 0 | 0 | 0 |\n -----------------------------------------------------------------------\n | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |\n -----------------------------------------------------------------------\n | 0 | 0 | 0 | 4 | 0 | 0 | 0 | 0 | 0 | 0 |\n -----------------------------------------------------------------------\n | 0 | 4 | 0 | 0 | 4 | 8 | 0 | 0 | 0 | 16 |\n -----------------------------------------------------------------------\n\n Score: 0\n\n\n\n Control: W(\u2191) A(\u2190) S(\u2193) D(\u2192) Q(quit) R(Restart)\n
\n

\u80cc\u666f

\n

\u6211\u89c9\u5f97\u547d\u4ee4\u884c\u7684\u7a0b\u5e8f\u6bd4\u8f83\u8d5b\u535a\u670b\u514b\uff0c\u4e00\u76f4\u60f3\u505a\u4e2a\u547d\u4ee4\u884c\u7684\u4ea4\u4e92\u7a0b\u5e8f\u3002\n\u76ee\u524d\u5728\u6e38\u620f\u516c\u53f8\uff0c\u867d\u7136\u6211\u4e0d\u662f\u6e38\u620f\u5de5\u7a0b\u5e08\uff0c\u4f46\u662f\u63a5\u89e6\u4e86\u4e00\u4e9b\u6e38\u620f\u884c\u4e1a\u7684\u4f18\u79c0\u5c0f\u4f19\u4f34\uff0c\u6211\u4e5f\u5fcd\u4e0d\u4f4f\u601d\u8003\u5173\u4e8e\u6e38\u620f\u7684\u4e3b\u9898\u3002

\n

\u6211\u60f3\u505a\u7684\u547d\u4ee4\u884c\u4ea4\u4e92\u5f0f\u7a0b\u5e8f\uff0c\u5176\u5b9e\u548c\u6e38\u620f\u7684\u601d\u60f3\u5185\u6838\u662f\u4e00\u81f4\u7684\u3002\u4e00\u62cd\u5373\u5408\u3002

\n

\u6211\u4ee5\u524d\u505a\u8fc7\u4e00\u70b9\u70b9\u7814\u7a76\u3002\u8bb0\u5f55\u4e86\u4e00\u4e9b\u7b14\u8bb0\u3002\u5173\u4e8e Ruby \u4e2d\u5982\u4f55\u5b9e\u73b0\u4ea4\u4e92\u5f0f\u547d\u4ee4\u884c\u7a0b\u5e8f\u3002\n\u672c\u6587\u4e5f\u662f\u5efa\u7acb\u5728\u8fd9\u4e2a\u57fa\u7840\u4e4b\u4e0a\u3002

\n\n

\u7528\u6700\u7b80\u5355\u7684\u65b9\u5f0f\u5b9e\u73b0\u4e86\u4e00\u4e2a [\u8d2a\u5403\u86c7]

\n\n

rb2048 \u5fc3\u8def\u5386\u7a0b

\n

rb2048 \u4eae\u70b9

\n

rb2048 \u6709\u8da3\u7684\u5730\u65b9\u5728\u4e8e\uff0c\u5728\u8bbe\u8ba1\u7684\u65f6\u5019\uff0c\u6ca1\u6709\u7b80\u5355\u5b9e\u73b0\u4e86\u4e4b\u3002\u6bd5\u7adf\u6709\u592a\u591a 2048 \u4e86\uff0c\u4e0d\u5dee\u8fd9\u4e00\u4e2a\u3002

\n

\u5bf9\u4e8e\u6211\u4e0d\u662f\u5b8c\u6210\u4e00\u4e2a\u4efb\u52a1\u3002\u7531\u4e8e\u6700\u8fd1\u4e24\u5929\u5173\u6ce8\u4e8e\u7ebf\u7a0b\u7684\u4f7f\u7528\uff0c\u4e8e\u662f\u6211\u628a\u7ebf\u7a0b\u65b9\u9762\u7684\u4f7f\u7528\u52a0\u5165\u5230 rb2048 \u3002\u8fd9\u7b97\u662f\u4e00\u4e2a\u5b9e\u9a8c\u6027\u7684\u4f8b\u5b50\u3002\u9a8c\u8bc1\u6211\u7684\u60f3\u6cd5\uff1a

\n

rb2048 \u5c06:

\n\n

\u8fd9\u4e09\u90e8\u5206\u5206\u522b\u7528\u5355\u72ec\u7684\u7ebf\u7a0b\u5b9e\u73b0\uff0c\u7528\u961f\u5217\u901a\u4fe1\u3002\u9ebb\u96c0\u867d\u5c0f\uff0c\u4e94\u810f\u4ff1\u5168\u3002\u867d\u7136\u7c97\u7cd9\uff0c\u4f46\u662f\u4ee3\u8868\u4e86\u6e38\u620f\u5f15\u64ce\u5178\u578b\u7684\u8bbe\u8ba1\u601d\u8def\u3002\n\uff08\u867d\u7136\u6211\u4e86\u89e3\u7684\u4e0d\u591a\uff09

\n

\u8ba4\u77e5\u53d8\u5316

\n

\u7b80\u5355\u8bf4\u8bf4\u6211\u6700\u8fd1\u7684\u601d\u8003\u5427:

\n

1 \uff09\u5bf9\u4e8e\u8ba1\u7b97\u673a\u4e0d\u540c\u9886\u57df\u8ba4\u8bc6\u53d1\u751f\u4e86\u53d8\u5316

\n

\u4ee5\u524d\u4f1a\u89c9\u5f97\uff1a\u6e38\u620f\u662f\u6e38\u620f\uff0cweb \u662f web \uff0c\u8bed\u8a00\u662f\u8bed\u8a00\uff0c\u5143\u7f16\u7a0b\u5c31\u662f\u5143\u7f16\u7a0b\u2026\u2026\u4e5f\u8bb8\u8fd8\u6709\u5f88\u591a\u6982\u5ff5\uff0c\u4f46\u662f\u6e10\u6e10\u73b0\u5728\u89c9\u5f97\u65e0\u975e\u662f\u4e00\u4ef6\u4e8b \u2014\u2014 \u7f16\u7a0b\u7f62\u4e86\u3002

\n

\u968f\u7740\u770b\u5230\u601d\u8003\u7684\u4e1c\u897f\u9010\u6e10\u53d8\u591a\uff0c\u5f88\u591a\u8ba1\u7b97\u673a\u9886\u57df\u7684\u95ee\u9898\uff0c\u5728\u6211\u7684\u89d2\u5ea6\u89c9\u5f97\u90fd\u4e00\u6837\u3002

\n

2 \uff09\u7b2c\u4e00\u6027\u539f\u7406 + \u4ea4\u6d41\uff0c\u5411\u5185\u4e60\u5f97

\n

\u8fd9\u6b21\u6478\u7740\u77f3\u5934\u8fc7\u6cb3\uff0c\u6bd4\u8f83\u65b0\u5947\u7684\u4f53\u9a8c\u5c31\u662f\uff0c\u4ece\u5f53\u521d\u4e00\u4e2a\u60f3\u6cd5\u5230\u539f\u7406\u7684\u8ba8\u8bba\u5230\u6700\u540e\u5b9e\u73b0\u3002\u4e3b\u8981\u662f\u601d\u8003\u63a8\u7406\uff0c\u8fd8\u6709\u548c\u4f18\u79c0\u7684\u540c\u4e8b\u7684\u804a\u5929\u4e2d\u4e60\u5f97 \uff08\u8fd9\u91cc\u611f\u8c22 @\u8c37\u795e)\u3002

\n\n

\u73b0\u5b9e\u4e2d\u6709\u5f88\u591a\u6e38\u620f\u5f15\u64ce\u3002\u4ed6\u4eec\u4e5f\u8bb8\u5185\u6709\u4e7e\u5764\uff0c\u4e0d\u8fc7\u5176\u5b9e\u662f\u5426\u7814\u7a76\u4ed6\u4eec\u4e5f\u4e0d\u91cd\u8981\u3002

\n

\u6211\u4e5f\u4e0d\u5728\u4e4e\u522b\u4eba\u7684\u5b9e\u73b0\uff0c\u6216\u8005\u66f4\u597d\u5730\u5b9e\u73b0\uff0c\u662f\u5426\u6709\u5b9e\u73b0\u8fc7\u4e86\u53ef\u4ee5\u53c2\u8003\u3002\u5176\u5b9e\u6ca1\u4ec0\u4e48\u53ef\u53c2\u8003\u7684\u3002\u53ea\u8981\u6211\u4eec\u81ea\u5df1\u60f3\u660e\u767d\u4e86\uff0c\u522b\u5fd8\u4e86\u6211\u4eec\u4e0a\u9762\u8bf4\u7684\uff0c\u4ed6\u4eec\u90fd\u662f\u4e00\u4ef6\u4e8b \u2014\u2014 \u7f16\u7a0b\u7f62\u4e86\u3002\n\u5f53\u6211\u4eec\u9762\u4e34\u65b0\u95ee\u9898\uff0c\u6211\u4eec\u4e5f\u4f1a\u52a0\u5f3a\u6211\u4eec\u7684 \u201c\u5f15\u64ce\u201d\u3002\u4ece\u601d\u60f3\u4e0a\uff0c\u4ed6\u4eec\u662f\u5e73\u7b49\u7684\u3002:P

\n

\u53ef\u80fd\u4e0e\u4ee5\u524d\u5411\u5916\u6c42\u77e5\uff0c\u73b0\u5728\u4f1a\u989d\u5916\u7684\u5411\u5185\u601d\u8003\u3002\u6bd4\u8f83\u795e\u5947\u7684\u4f53\u9a8c\u662f\uff0c\u4e00\u4e9b\u4e1c\u897f\u542c\u4e2a\u5927\u6982\uff0c\u4e5f\u80fd\u76f2\u731c\u4e2a\u4e03\u516b\u5206\u3002

\n

\u4ece\u6e38\u620f\u5f00\u59cb\u804a\u5427

\n

\u6e38\u620f\u4e4b\u96be

\n

\u5176\u5b9e 2048 \u6ca1\u5565\u597d\u804a\uff0c\u5199 2048 \u7684\u80cc\u540e\u662f\u5bf9\u6e38\u620f\u7684\u4e00\u4e9b\u601d\u8003\u3002

\n

\u5176\u5b9e\u6e38\u620f\u662f\u4e00\u4e2a\u6bd4\u8f83\u7279\u522b\u7684\u5b58\u5728\u3002\u4ed6\u662f\u4e00\u79cd\u6bd4\u8f83\u7279\u6b8a\u7684\u7a0b\u5e8f\uff0c\u7279\u6b8a\u5728\u54ea\u513f\u5462\uff1f

\n

1 \uff09\u4ed6\u662f\u6301\u7eed\u4ea4\u4e92\u7a0b\u5e8f

\n

\u4e0d\u540c\u4e8e\u7b80\u5355\u7684\u811a\u672c\uff0c\u8dd1\u5b8c\u7ed3\u675f\u3002\u6216\u8005\u4f20\u9012\u4e00\u4e2a\u521d\u59cb\u53c2\u6570\uff0c\u5c31\u50cf\u51fd\u6570\u4e00\u6837\u8fd0\u884c\u5b8c\u7ed3\u675f\u3002

\n

\u4ed6\u662f\u4e00\u4e2a\u6301\u7eed\u4ea4\u4e92\u7684\u8fc7\u7a0b\uff0c\u968f\u7740\u65f6\u95f4\u7d2f\u8ba1\u6e38\u620f\u7684\u65b9\u65b9\u9762\u9762\u90fd\u5728\u53d8\u5316\u3002

\n

2 \uff09\u591a\u9762\u5e73\u8861

\n

\u4e0d\u540c\u4e8e\u4f60\u5199\u4e00\u6bb5 function \u5c31\u7ed3\u675f\u4e86\u3002\u6e38\u620f\u8981\u5728\u8fd0\u884c\u7684\u751f\u547d\u5468\u671f\u91cc\uff1a

\n\n

\u5728\u81f3\u5c11\u8fd9\u4e09\u4e2a\u65b9\u9762\u4e92\u76f8\u4f5c\u7528\u3002

\n

\u8fd8\u53ef\u80fd\u6709:

\n\n

\u5176\u4ed6\u5468\u8fb9\u5e76\u4e0d\u5c55\u5f00

\n

3 \uff09\u7a33\u5b9a\u7684\u5e27\u7387

\n

\u5982\u679c\u662f 60HZ \u7684\u6e38\u620f\uff0c\u5fc5\u987b\u5728 16.6ms \u5185\u5b8c\u6210\u52a8\u4f5c\u8fdb\u884c\u5237\u65b0\u3002

\n

\u8fd9\u4e5f\u4e0d\u662f\u666e\u901a\u4e1a\u52a1\u811a\u672c\u3001\u7a0b\u5e8f\u4e00\u76f4\u8dd1\u81ea\u5df1\u7684\u7ebf\u6027\u903b\u8f91\u5c31\u7b97\u4e86\uff0c\u6839\u672c\u4e0d\u5173\u5fc3\u65f6\u95f4\u3002

\n

4 \uff09\u5bc6\u96c6\u5bf9\u8c61\u8ba1\u7b97

\n

\u7b80\u5355\u7684\u6e38\u620f\u8fd8\u597d\uff0c\u4f20\u7edf\u7684\u6a21\u5f0f\u662f\u9762\u5411\u5bf9\u8c61\u5efa\u6a21\uff0c\u4e00\u5207\u770b\u8d77\u6765\u8fd8\u7b97\u81ea\u7136\u3002

\n

\u4f46\u662f\u4e5f\u51fa\u73b0\u4e86\u4e07\u4eba\u540c\u53f0\u7684\u6e38\u620f\uff0c\u8fd9\u91cc\u4f20\u7edf\u7684\u7f16\u7a0b\u6a21\u5f0f\u5df2\u7ecf\u6ee1\u8db3\u4e0d\u4e86\u6e38\u620f\u5bf9\u8c61\u7684\u904d\u5386\u4e86\uff0c\u5f88\u5feb\u4f1a\u8fbe\u5230\u6027\u80fd\u74f6\u9888\u3002

\n

\u8fd9\u51e0\u5e74\uff0c\u51fa\u73b0\u4e86 ECS \u67b6\u6784\uff08 Entity-Component-System \uff09\u3002

\n
\n

\u6d45\u8c08\u300a\u5b88\u671b\u5148\u950b\u300b\u4e2d\u7684 ECS \u6784\u67b6

\n
\n

\u5c0f\u7ed3\uff1a

\n

\u5176\u5b9e\u8fd8\u6709\u5404\u79cd\u53d1\u6563\u3002\u5982\u4f55\u4f7f\u7528 CPU \u3001GPU \u52a0\u901f\u6e32\u67d3\uff0c\u8fd9\u5c31\u4e0d\u518d\u63d0\u4e86\u3002

\n

\u6e38\u620f\u662f\u4e00\u4e2a\u975e\u5e38\u7279\u6b8a\u7684\u5b58\u5728\uff0c\u5b83\u610f\u5473\u7740\u5bc6\u96c6\u578b\u8ba1\u7b97\u3001\u5bc6\u96c6\u578b IO \u6df7\u5408\u51fa\u73b0\u7684\u573a\u666f\u3002\u6211\u7406\u89e3\u662f\u6bd4 Web \u590d\u6742\u5728\u53e6\u4e00\u4e2a\u7ef4\u5ea6\u4e0a\u3002

\n

\u6e38\u620f\u6d89\u53ca\u5230 \u7f16\u7a0b\u67b6\u6784\u3001\u7f51\u7edc\u3001\u56fe\u5f62\u5b66\u3001\u7f8e\u672f\u8bbe\u8ba1\u3001\u8d44\u6e90\u52a0\u8f7d\u2026\u2026 \u8bf8\u591a\u4e30\u5bcc\u7684\u8bdd\u9898\u3002

\n

\u8fd9\u4e9b\u5c31\u4e0d\u662f\u6211\u8fd9\u4e2a\u95e8\u5916\u6c49\u9760\u7ba1\u7aa5\u8821\u6d4b\u80fd\u591f\u8bf4\u5f97\u6e05\u7684\u3002\u6211\u4eca\u5929\u53ef\u4ee5\u53ea\u8c08\u8c08\u6211\u5bf9\u6e38\u620f\u7684\u7406\u89e3\u548c\u8ba4\u8bc6\uff0c\u4ee5\u53ca\u6784\u5efa 2048 \u7684\u601d\u8003\u3002

\n

\u6e38\u620f\u57fa\u672c\u6784\u6210

\n

\u5176\u5b9e\u4e00\u4e2a\u57fa\u672c\u6e38\u620f\u53ef\u4ee5\u7528\u5982\u4e0b\u4ee3\u7801\u63cf\u8ff0\uff1a

\n
loop do\n IOEvent\n UpdateGameData\n Render\nend\n
\n

\u6e38\u620f\u5904\u5728\u4e00\u4e2a\u4e3b\u5faa\u73af\u4e2d\uff0c\u6211\u4eec\u4f9d\u6b21\u8981\u5904\u7406\u7528\u6237\u8f93\u5165\u4e8b\u4ef6\uff0c\u6839\u636e\u7528\u6237\u8f93\u5165\u4e8b\u4ef6\u8fdb\u884c\u6e38\u620f\u6a21\u578b\u7684\u53d8\u5316\uff0c\u6700\u540e\u518d\u628a\u6570\u636e\u6e32\u67d3\u5728\u5c4f\u5e55\u4e0a\u3002

\n

\u8fd9\u662f\u4e00\u4e2a\u5355\u7ebf\u7a0b\uff0c\u4e3b\u5faa\u73af\u7684\u4f8b\u5b50\u3002

\n

\u73b0\u5b9e\u4e2d\u6bcf\u4e2a\u90e8\u5206\u90fd\u53ef\u4ee5\u989d\u5916\u53d8\u5f97\u590d\u6742\u3002\u4e5f\u53ef\u4ee5\u7528\u7ebf\u7a0b\u5355\u72ec\u5b9e\u73b0\u3002\u4e00\u5207\u770b\u9700\u6c42\u3002

\n

\u6e38\u620f\u4e0e\u4ea4\u4e92\u5e94\u7528\u7a0b\u5e8f

\n

\u4f60\u4f1a\u53d1\u73b0\u6e38\u620f\u5c31\u662f\u4ea4\u4e92\u7a0b\u5e8f\u3002

\n

\u4e0a\u9762\u7684\u4e09\u90e8\u5206\uff0c\u4f60\u4e5f\u53ef\u4ee5\u548c MVC \u5f3a\u884c\u626f\u5728\u4e00\u8d77\u3002

\n\n

MVC \u7684\u5178\u578b\u7a0b\u5e8f\uff0c\u9664\u4e86\u684c\u9762\u8f6f\u4ef6\uff0cWeb \u4e5f\u7b97\u662f\uff0cApp \u4e5f\u7b97\u3002

\n

\u770b\u4f3c\u662f\u5728\u8bf4\u6e38\u620f\uff0c\u5b9e\u9645\u4e0a\u4ed6\u4eec\u662f\u4e00\u56de\u4e8b\u3002

\n

\u6e38\u620f\u5f15\u64ce\u7684\u79d8\u5bc6

\n

\u6e38\u620f\u5f15\u64ce\u5176\u5b9e\u5c31\u662f\u6846\u67b6\uff0c\u5f88\u4f69\u670d\u4ed6\u4eec\u4f1a\u8d77\u540d\u5b57\u3002

\n

\u6846\u67b6\u3001\u5f15\u64ce\u5176\u5b9e\u662f\u4e00\u4e2a\u4e1c\u897f\uff0c\u4ed6\u4eec\u7684\u7279\u5f81\u5c31\u662f\u4e00\u4e2a\u534a\u6210\u54c1\u7684\u8f6f\u4ef6\u3002

\n
loop do\n IOEvent\n UpdateGameData\n Render\nend\n
\n

\u6bd4\u5982\u8fd9\u4e2a\u6e38\u620f\u5faa\u73af\uff0c\u5982\u679c\u6211\u4eec\u5c01\u88c5\u4e86\u4e3b\u5faa\u73af\uff0c\u5c01\u88c5\u4e86\u4e8b\u4ef6\u5bf9\u8c61\u3002\u5bf9\u5916\u66b4\u9732\u4e86\u4e00\u4e9b\u751f\u547d\u5468\u671f\u3002\n\u8fd9\u79cd\u534a\u6210\u54c1\u8f6f\u4ef6\u5c31\u662f \u6240\u8c13\u7684\u6846\u67b6\uff0c\u5728\u6e38\u620f\u9886\u57df\u5c31\u662f\u5f15\u64ce\u3002

\n

\u4f5c\u4e3a\u4e0b\u6e38\uff0c\u6e38\u620f\u5f15\u64ce /\u6846\u67b6\u7684\u4f7f\u7528\u8005\u6765\u8bf4\uff0c\u6211\u4eec\u5199\u7684\u7a0b\u5e8f\u5c31\u50cf\u586b\u7a7a\u4e00\u6837\u548c\u4e3b\u5faa\u73af\u5de5\u4f5c\u5728\u4e00\u8d77\u3002

\n

\u4e3b\u5faa\u73af\u51b3\u5b9a\u4e86\u4ec0\u4e48\u662f\u6846\u67b6\u3001\u4ec0\u4e48\u662f\u5e93

\n

\u6240\u4ee5\u6211\u4e2a\u4eba\u89c9\u5f97\uff0c\u51b3\u5b9a\u4e86\u4ec0\u4e48\u662f \u6846\u67b6 Framework \u548c \u5e93 Library \u7684\u672c\u8d28\u533a\u522b\u662f \u2014\u2014 \u4e3b\u5faa\u73af\u3002

\n

\u5f53\u4f60\u7684\u7a0b\u5e8f\u662f\u4e00\u79cd\u53ef\u88ab\u8c03\u7528\u7684\u72b6\u6001\uff0c\u90a3\u4e48\u57fa\u672c\u4e0a\u4f60\u7684\u7a0b\u5e8f\u53ef\u4ee5\u770b\u6210\u4e00\u4e2a lib\n\u5f53\u4f60\u7684\u7a0b\u5e8f\u5982\u679c\u62e5\u6709\u4e86\u4e3b\u5faa\u73af\u7684\u72b6\u6001\uff0c\u57fa\u672c\u5ba3\u544a\u4e86\u4e0d\u53ef\u88ab\u76f4\u63a5\u8c03\u7528\u3002\u90a3\u4e48\u5b83\u5176\u5b9e\u662f\u4e00\u4e2a Framework \u4e86\u3002\u9664\u4e86\u5404\u79cd Pattern \u5f88\u5c11\u89c1\u5230\u4e3b\u5faa\u73af\u7684 lib \u5c55\u793a\uff0c\u4e0d\u5b58\u5728\u7684\u539f\u56e0\u662f\u56e0\u4e3a\u62e5\u6709\u4e3b\u5faa\u73af\u7684\u7a0b\u5e8f\uff0c\u4e00\u822c\u4ee5\u5177\u4f53\u7684\u8f6f\u4ef6\u5f62\u6001\u51fa\u6765\uff1a

\n
    \n
  1. \u67d0\u79cd\u8bed\u8a00\uff0c\u6bd4\u5982 \u81ea\u5e26\u8c03\u5ea6\u7684 golang \u3001\u81ea\u5e26 EventLoop \u7684 Javascript \u5f15\u64ce V8
  2. \n
  3. \u67d0\u79cd\u6846\u67b6\uff0c\u6bd4\u5982 Web \u6846\u67b6\u81ea\u5e26\u76d1\u542c\u5faa\u73af
  4. \n
  5. \u67d0\u79cd\u5f15\u64ce\uff0c\u6bd4\u5982 \u6e38\u620f\u5f15\u64ce
  6. \n
\n

Framework \u5f0f\u7684\u7a0b\u5e8f\uff0c\u4f60\u7684\u5de5\u4f5c\u4efb\u52a1\u5c31\u4f1a\u8f6c\u5411\u719f\u6089\u8fd9\u4e2a\u7a0b\u5e8f\u66b4\u9732\u7684\u5bf9\u8c61\uff0c\u671f\u5f85\u4f60\u7684\u7a0b\u5e8f\u548c\u4e3b\u5faa\u73af\u80fd\u4e00\u8d77\u5de5\u4f5c\u3002

\n

\u7f16\u7a0b\u8bed\u8a00\u4f1a\u662f\u6e38\u620f\u7684\u74f6\u9888\u4e48\uff1f

\n

\u6211\u4eec\u518d\u6765\u804a\u804a\u6e38\u620f\u5f15\u64ce\u548c\u7f16\u7a0b\u8bed\u8a00\u3002

\n

Unity \u7684\u80cc\u540e\u662f C# \u652f\u6491\uff1b\u865a\u5e7b\u5f15\u64ce\u7684\u80cc\u540e\u662f C++\u3002\u4ed6\u4eec\u91c7\u7528\u4e86\u66f4\u5e95\u5c42\u7684\u8bed\u8a00\u3002\u90a3\u4e48\u95ee\u9898\u6765\u4e86\uff0c\u7f16\u7a0b\u8bed\u8a00\u4f1a\u6210\u4e3a\u5236\u7ea6\u6e38\u620f\u7684\u74f6\u9888\u4e48\uff1f

\n

\u8fd9\u4e5f\u662f\u6211\u81ea\u5df1\u601d\u8003\u7684\u4e00\u4e2a\u95ee\u9898\u3002

\n

\u6211\u4eec\u53ef\u80fd\u4f1a\u5f88\u7c97\u66b4\u5730\u89c9\u5f97 \u52a8\u6001\u8bed\u8a00\u666e\u904d\u6162\uff0c\u5f53\u7136\u662f\u8d8a\u63a5\u8fd1\u5e95\u5c42\u8d8a\u597d\u3002\u5176\u5b9e\u6211\u66f4\u60f3\u77e5\u9053\uff0c\u5982\u6b64\u8fd9\u6837\u9009\u62e9\u7684\u6807\u51c6\u5728\u54ea\u513f\uff1f

\n

\u5176\u5b9e\u6211\u4eec\u53ef\u4ee5\u601d\u8003\u4e0b\uff0c\u8fd9\u4e2a\u7ed3\u8bba\u4e0d\u96be\u83b7\u5f97\u3002

\n

\u52a8\u6001\u8bed\u8a00\u771f\u7684\u6162\u4e48\uff1f

\n

\u5176\u5b9e\u52a8\u6001\u8bed\u8a00\u5728\u6267\u884c\u4e00\u4e2a\u547d\u4ee4\u7684\u65f6\u5019\uff0cRuby \u8fd9\u79cd\u6700\u540e C \u5b9e\u73b0\uff1b Golang \u6700\u540e\u4e5f\u843d\u5728 C \uff08 Golang \u5b9e\u73b0\u81ea\u4e3e\u4e4b\u540e\uff0c\u90a3\u5c31\u7528\u6c47\u7f16\u601d\u8003\u5427\uff09\u3002\u5176\u5b9e\u4ed6\u4eec\u5728\u6267\u884c\u4e00\u4e2a\u5177\u4f53\u64cd\u4f5c\u7684\u65f6\u5019\uff0c\u6570\u91cf\u7ea7\u4e00\u81f4\u7684\u3002

\n

\u4ed6\u4eec\u5176\u5b9e\u5dee\u4e0d\u591a\u3002

\n

\u901f\u5ea6\u5dee\u8ddd\u5728\u54ea\u513f\u5462\uff1f

\n

1 \uff09\u8f7d\u5165\u73af\u5883

\n

C \u3001Golang \u8fd9\u79cd\u53ef\u4ee5\u6253\u5305\u6210\u4e8c\u8fdb\u5236\u7684\u8bed\u8a00\u3002\u4ed6\u7f16\u8bd1\u9636\u6bb5\u4f1a\u628a\u9700\u8981\u6267\u884c\u7684\u4ee3\u7801\u7f16\u8bd1\u6210\u4e8c\u8fdb\u5236\u3002

\n

\u6240\u4ee5\u6267\u884c\u7684\u65f6\u5019\u8f7d\u5165\u7684\u662f\u6240\u9700\u8981\u7528\u5230\u7684\u90e8\u5206\u529f\u80fd\u3002

\n

Python \u3001Ruby \u8fd9\u79cd\u5176\u5b9e \u4e8c\u8fdb\u5236\u662f\u8bed\u8a00\u7684\u89e3\u91ca\u5668\u3002\u8fd0\u884c\u7684\u65f6\u5019\u66f4\u591a\u7684\u65f6\u95f4\u82b1\u8d39\u5728\u52a0\u8f7d\u89e3\u91ca\u5668\u3002

\n

\u4e0d\u8fc7\uff0c\u5f53\u4f60\u7684\u7a0b\u5e8f\u590d\u6742\u5230\u6d89\u53ca\u5927\u91cf IO \u3001\u57fa\u7840\u5e93\u7684\u65f6\u5019\uff0cGolang \u7684\u6253\u5305\u7ed3\u679c\u4f1a\u8d8b\u5411\u4e8e\u63a5\u8fd1\u4e00\u4e2a\u89e3\u91ca\u5668\u7684\u5927\u5c0f\uff0c\u6bd4\u5982 Ruby \u5dee\u4e0d\u591a\u5728 30M \u5de6\u53f3\u3002

\n

\u6211\u66fe\u7ecf\u6bd4\u8f83\u8fc7\uff1a

\n

Golang \u7684\u4e00\u4e2a\u9879\u76ee\u547d\u4ee4\u884c\u7f16\u8f91\u5668 micro \u3001Ruby \u7684\u4e00\u4e2a\u9879\u76ee\u547d\u4ee4\u884c\u7f16\u8f91\u5668 diakonos

\n

micro \u8fd0\u884c\u5185\u5b58 16M \uff0c\u4e5f\u5c31\u662f\u4ed6\u672c\u5730\u5927\u5c0f\uff1b diakonos \u8fd0\u884c\u5185\u5b58 30M \uff0c\u4e5f\u5c31\u662f Ruby \u89e3\u91ca\u5668\u5dee\u4e0d\u591a\u7684\u5927\u5c0f\u3002ruby \u4ee3\u7801\u4f1a\u6267\u884c\u624d\u52a0\u8f7d\uff0c\u6240\u4ee5\u53ef\u4ee5\u5ffd\u7565\u4e0d\u8ba1\u3002

\n

\u6700\u5927\u7684\u5dee\u8ddd\uff0c\u5728\u4e8e 30-16 \u7684\u8f7d\u5165\u901f\u5ea6\u5dee\uff0c\u8fd9\u4e2a\u91cf\u7ea7\u662f\u4e0d\u540c\u7684\u3002

\n

2 \uff09\u8bed\u8a00\u6784\u4ef6

\n

C \u8bed\u8a00\u5c31\u50cf\u662f\u4e00\u4e2a\u9ad8\u7ea7\u4e00\u70b9\u7684\u6c47\u7f16\u3002C \u7684\u89d2\u5ea6\u4e00\u5207\u90fd\u9700\u8981\u624b\u52a8\u7ba1\u7406\u3002\u90a3\u4e48\u5176\u5b9e\u5bf9\u4e8e\u5e95\u5c42\u8bed\u8a00\uff0c\u66f4\u73b0\u5b9e\u4e00\u70b9\u7684\u662f\u4f1a\u81ea\u5df1\u624b\u52a8\u5b9e\u73b0\u6570\u636e\u7ed3\u6784\u3002

\n

Ruby \u8fd9\u79cd\u52a8\u6001\u8bed\u8a00\uff0c\u5185\u90e8\u9ed8\u8ba4\u4f1a\u6709\u4e00\u4e2a\u6570\u636e\u7ed3\u6784\u3002

\n

\u4e3e\u4e2a\u4f8b\u5b50\uff1a

\n

\u6bd4\u5982 a = \"GAME\"

\n

C \u8bed\u8a00\u5b9e\u9645\u4e0a\u53ea\u4f1a\u624b\u52a8\u521b\u5efa \"GAME\" \u56db\u4e2a\u5b57\u7b26

\n

Python \u5e95\u5c42\u53ef\u80fd\u521b\u5efa\u4e00\u4e2a 20 \u5b57\u7b26\u957f\u5ea6\u7684\u6570\u7ec4\u3002\u5b58 GAME \u3002\u4e5f\u6709\u597d\u5904\uff0c\u53ef\u4ee5\u4e0d\u5b9a\u957f\u652f\u6301\u52a8\u6001\u6269\u5bb9\u3002

\n

\u5728\u751f\u6210\u8bed\u8a00\u6784\u5efa\u7684\u65f6\u5019\u5b58\u5728\u901f\u5ea6\u5dee\u3002\n\u52a8\u6001\u8bed\u8a00\u7b49\u4e8e\u591a\u521b\u5efa\u4e86\u5f88\u591a\u8bed\u8a00\u5728\u5185\u5b58\u91cc\u7684\u89e3\u6784\u3002

\n

3 \uff09\u89e3\u6790\u65f6\u95f4

\n

\u4e8c\u8fdb\u5236\u7684\u6587\u4ef6\uff0c\u76f4\u63a5\u8f7d\u5165\u5185\u5b58\u6267\u884c\u3002

\n

\u52a8\u6001\u8bed\u8a00\u6709\u4e00\u4e2a\u89e3\u6790\u7684\u8fc7\u7a0b\u3002\u5f53\u7136\uff0c\u4e5f\u6709\u4f18\u5316\u7a7a\u95f4\uff0c\u6211\u4eec\u53ef\u4ee5\u63d0\u524d\u7f16\u8bd1\u52a8\u6001\u8bed\u8a00\u4e3a\u865a\u62df\u673a\u5b57\u8282\u7801\u3002\u8fd9\u6837\u5c31\u83b7\u5f97\u4e86 \u5bf9\u4e8e\u89e3\u91ca\u5668\u662f\u4e8c\u8fdb\u5236\u7c7b\u4f3c\u7684\u4e1c\u897f\u3002

\n

4 \uff09 GC \u65f6\u95f4

\n

\u548c C \u8bed\u8a00\u76f8\u6bd4\uff0cPython \u3001Ruby \u81ea\u5e26 GC \u3002

\n

\u4ed6\u4eec\u5b58\u5728\u4e00\u4e2a \u5fc5\u987b GC \u6682\u505c\u7684\u90a3\u4e48\u4e00\u4e2a\u95ee\u9898\u3002C \u8bed\u8a00\u7684\u7b56\u7565\u662f\u624b\u52a8\u56de\u6536\u3002

\n

\u53cc\u7f13\u51b2\u6a21\u5f0f

\n

\u6211\u4eec\u597d\u50cf\u5217\u4e3e\u4e86\u4e00\u5927\u5806 \u52a8\u6001\u8bed\u8a00\u7684\u7f3a\u70b9\u4f3c\u7684\u3002\u5b9e\u9645\u4e0a\u81ea\u52a8\u7ba1\u7406\u7684\u6570\u636e\u7ed3\u6784\u3001\u81ea\u5e26 GC \u3001\u53ef\u4ee5\u52a8\u6001\u7684\u7f16\u8bd1\u6267\u884c\u2026\u2026 \u8fd9\u4e9b\u90fd\u662f\u52a8\u6001\u8bed\u8a00\u7684\u7f3a\u70b9\u3002

\n

\u867d\u7136\u4ed8\u51fa\u4e86\u4e9b\u8bb8\u65f6\u95f4\u7684\u4ee3\u4ef7\u3002\u53ea\u8981\u6211\u4eec\u4e0d\u6ee5\u7528\u8bed\u8a00\u6784\u4ef6 \u548c \u7279\u522b\u70c2\u7684\u7b97\u6cd5\uff0c\u771f\u662f\u5de7\u5999\u7684\u63a5\u8fd1\u5e95\u5c42\u9ad8\u6548\u7684\u5b9e\u73b0\u3002

\n

\u5176\u5b9e\u6211\u60f3\u8bf4\uff0c\u52a8\u6001\u8bed\u8a00\u81f3\u5c11\u5728\u76ee\u6807\u4e0a\u4e0d\u662f\u7279\u522b\u5927\u7684\u74f6\u9888\u3002

\n

Java \u4e5f\u6709\u6e38\u620f\u7684\u4f8b\u5b50\uff1b C# \u4e5f\u662f\u81ea\u5e26 GC \u3002GC \u4e0d\u4f1a\u662f\u74f6\u9888\u3002

\n

\u8bed\u8a00\u7684\u901f\u5ea6\u4e0d\u4f1a\u7edd\u5bf9\u610f\u4e49\u4e0a\u6210\u4e3a\u4e00\u4e2a\u6e38\u620f\u7ec4\u6210\u7684\u963b\u788d\u3002

\n

EVE \u8fd9\u6837\u7684\u5927\u578b\u6e38\u620f\uff0c\u5185\u90e8\u4f7f\u7528\u4e86 \u5de8\u6162\u7684 Python \u5c31\u53ef\u4ee5\u8bf4\u660e\u95ee\u9898\u3002

\n

\u4e4b\u6240\u4ee5\u8bed\u8a00\u4e0d\u4e00\u5b9a\u6784\u6210\u62d6\u6162\u6e38\u620f\u7684\u539f\u56e0\uff0c\u8fd8\u6709\u4e00\u4e2a\u5c31\u662f\u6e38\u620f\u548c\u5c4f\u5e55\u7684\u5237\u65b0\u673a\u5236 \u2014\u2014 \u53cc\u7f13\u51b2\u6a21\u5f0f\u3002

\n

\u5176\u5b9e\u53ef\u4ee5\u7406\u89e3\u4e3a\u4e00\u4e2a \u5185\u5b58\u7a7a\u95f4\uff0c\u6211\u4eec\u79f0\u4e4b\u4e3a Buffer \u3002\u6211\u4eec\u6709\u4e24\u4e2a Buffer \uff0c\u5206\u522b\u53eb A Buffer \u3001B Buffer \u3002

\n

\u663e\u793a\u5668\u5148\u4ece A Buffer \u4e2d\u8bfb\u53d6\u6570\u636e\u6e32\u67d3\u5c4f\u5e55\u3002\u6211\u4eec\u7a0b\u5e8f\u5199\u5165 B Buffer \uff0c\u7b49\u6211\u4eec\u771f\u7684\u5199\u5b8c\u4e86\uff0c\u53ef\u6162\u6216\u8005\u5feb\uff0c\u4f46\u662f\u65e0\u6240\u8c13\uff0c\u53cd\u6b63\u5c4f\u5e55\u8fd9\u65f6\u5019\u5728\u7a33\u5b9a\u7684\u8bfb\u53d6 A Buffer \u5185\u5bb9\u3002\u6211\u4eec\u8ba1\u7b97\u5b8c\u6bd5\uff0cB Buffer \u4e2d\u5199\u5165\u4e86\u6211\u4eec\u60f3\u8981\u7684\u4e1c\u897f\uff0c\u8fd9\u65f6\u5019\u53ea\u8981\u628a\u663e\u793a\u5668\u8bfb\u53d6\u7684\u6307\u9488\u6307\u5411 B Buffer \uff0c\u4e0b\u6b21\u5c4f\u5e55\u5c31\u4f1a\u83b7\u5f97\u6211\u4eec\u60f3\u8981\u7684\u753b\u9762\u3002\u8fd9\u5c31\u662f\u53cc\u7f13\u51b2\u6a21\u5f0f\u3002\u7531\u4e8e\u5b58\u5728\u53cc\u7f13\u51b2\u89e3\u6784\uff0c\u7b97\u5feb\u548c\u5feb\u6162\uff0c\u81f3\u5c11\u4e0d\u4f1a\u6210\u4e3a\u753b\u9762\u6495\u88c2\u7684\u539f\u56e0\u3002

\n
\n

rb2048 \u4f7f\u7528\u4e86 Curses \u5e93\u6765\u7ed8\u5236\u754c\u9762\uff0c\u800c Curses \u5185\u90e8\u4f7f\u7528\u4e86\u53cc\u7f13\u51b2\u6a21\u5f0f\u3002

\n
\n

\u7ebf\u7a0b\u548c\u534f\u7a0b\u7684\u8ba8\u8bba

\n

\u6211\u4eec\u81ea\u5df1\u7814\u7a76\u4e86\u4e24\u5929\u7ebf\u7a0b\u548c\u961f\u5217\u3002\u4e3b\u8981\u662f Ruby \u7684\u5b9e\u73b0\u3002

\n

\u8fd9\u91cc\u4e0d\u6559\u7ebf\u7a0b\u548c\u534f\u7a0b\uff0c\u53ea\u8bb0\u5f55\u6211\u89c9\u5f97\u597d\u73a9\u7684\u4ea4\u6d41\u7ed3\u679c\u3002

\n

Ruby \u7ebf\u7a0b\u7684\u95ee\u9898

\n

\u7f3a\u70b9\uff1a

\n

Ruby \u5b58\u5728\u7ebf\u7a0b\u9501\uff0c\u8fd9\u5bfc\u81f4\u6bcf\u4e00\u65f6\u523b\u53ea\u80fd\u8fd0\u884c\u4e00\u4e2a\u7ebf\u7a0b\u3002\u7ebf\u7a0b\u5c31\u50cf\u80cc\u540e\u867d\u7136\u6709\u5f88\u591a\u5de5\u4eba\uff0c\u4f46\u662f\u53ea\u80fd\u4ea4\u66ff\u7684\u4e00\u4eba\u4e00\u9524\u5b50\u3002

\n

\u8fd9\u80cc\u540e\u7684\u539f\u56e0\u5728\u4e8e Ruby \u8003\u8651\u5b89\u5168\u66f4\u591a\u4e00\u70b9 \u2014\u2014 \u7ebf\u7a0b\u5b89\u5168\u3002

\n

\u8fd9\u6837\u7684\u591a\u7ebf\u7a0b\u65e0\u6cd5\u5229\u7528 CPU \u591a\u6838\u5fc3\u5e76\u884c\u7684\u7279\u70b9\u3002\u5e0c\u671b\u5229\u7528\u591a\u6838\u7684\uff0c\u53ef\u4ee5\u53bb\u7528 JRuby \uff0c\u56e0\u4e3a Java \u5e95\u5c42\u6ca1\u6709\u52a0\u9501\u3002

\n

Ruby3 \u4e2d\u4e5f\u6709\u4e86\u65e0\u9501\u7ebf\u7a0b\u7684\u66ff\u4ee3\u54c1 Ractor \u4e5f\u53ef\u4ee5\u4e86\u89e3\u4e0b\u3002

\n

CRuby \u5982\u679c\u60f3\u5229\u7528\u591a\u6838\u5fc3\u53ef\u4ee5\u4f7f\u7528\u8fdb\u7a0b\u66ff\u4ee3\u7ebf\u7a0b\u3002\u5982\u679c\u8bbe\u8ba1\u5f97\u5f53\uff0c\u5176\u5b9e\u5dee\u4e0d\u591a\u3002Ruby \u91cc\u9762 Webserver \u6709\u540d\u6c14\u7684 Puma \u91c7\u7528\u7684\u5c31\u662f\u591a\u8fdb\u7a0b\u5b9e\u73b0\u3002

\n

\u4f18\u70b9\uff1a

\n

\u52a0\u4e0a\u9501\u6700\u5927\u597d\u5904\u662f\u7ebf\u7a0b\u5b89\u5168\uff0c\u4f60\u53ef\u4ee5\u81ea\u7531\u7684\u7f16\u7801\uff0cRuby \u5e2e\u4f60\u52a0\u9501\u3002\u8fd9\u6837\u591a\u7ebf\u7a0b\u8bbf\u95ee\u53d8\u91cf\u7684\u65f6\u5019\uff0c\u4e0d\u4f1a\u51fa\u9519\u3002

\n

\u4f46\u662f\u4f60\u9000\u51fa\u6765\u60f3\uff0c\u53cd\u6b63\u4f60\u81ea\u5df1\u4e5f\u8981\u52a0\u9501\u554a\uff0c\u8c01\u52a0\u4e0d\u662f\u52a0\u3002Ruby \u9ed8\u8ba4\u7684\u7ebf\u7a0b\u5176\u5b9e\u4e66\u5199\u8d77\u6765\u975e\u5e38\u53cb\u597d\u3002

\n

\u8fdb\u7a0b\u3001\u7ebf\u7a0b\u3001\u534f\u7a0b \u50bb\u50bb\u5206\u4e0d\u6e05\u695a

\n

\u6211\u89c9\u5f97\u518d\u8fd9\u6837\u4ecb\u7ecd\u8fd9\u4e09\u4e2a\u6982\u5ff5\uff0c\u8fd9\u6587\u7ae0\u592a\u5197\u957f\u4e86\u3002

\n

\u76f4\u63a5\u8bf4\u7ed3\u8bba\u5427\uff0c\u76f4\u89c2\u4e0a\uff0c\u8fd9\u4e09\u8005\u5b58\u5728\u91cf\u7ea7\u5dee\uff0c\u4e0d\u4ec5\u4f53\u73b0\u5728\u7a7a\u95f4\u8d44\u6e90\uff0c\u65f6\u95f4\u8d44\u6e90\u90fd\u5dee\u4e0d\u591a\u3002

\n

\u8fdb\u7a0b >> \u7ebf\u7a0b >> \u534f\u7a0b

\n

\u6bd4\u5982\u4e00\u53f0\u673a\u5668 4G \u5185\u5b58\uff1a

\n

\u53ef\u80fd\u53ea\u80fd\u5b9e\u9645\u751f\u6210\u51e0\u767e\u4e2a\u8fdb\u7a0b\u5c31\u4e0d\u592a\u884c\u4e86\u3002\n\u540c\u6837\uff0c\u53ef\u4ee5\u751f\u6210\u51e0\u5343\u4e2a\u7ebf\u7a0b\uff0c\u5c31\u52a8\u4e0d\u4e86\u4e86\u3002\n\u534f\u7a0b\u53ef\u4ee5\u751f\u6210\u51e0\u5341\u4e07\u4e2a\u3002

\n

\u4ed6\u4eec\u5927\u6982\u5c31\u662f\u8fd9\u4e2a\u5dee\u8ddd(\u6709\u66f4\u597d\u6570\u636e\u652f\u6301\u7684\uff0c\u8bf7\u8054\u7cfb\u6211)\u3002

\n

\u4ed6\u4eec\u5207\u6362\u4e0a\u4e0b\u6587\u7684\u65f6\u95f4\u4e5f\u9075\u5faa\u8fd9\u4e2a\u6bd4\u8f83\u5173\u7cfb\u3002

\n

\u6240\u4ee5\u6211\u4eec\u4e00\u822c\u7684\u7b56\u7565\uff0c\u5c3d\u91cf\u591a\u7528\u534f\u7a0b&\u7ebf\u7a0b\uff0c\u5c11\u7528\u8fdb\u7a0b\u3002

\n

\u5982\u679c\u4efb\u52a1\u72ec\u7acb\u8fd0\u884c\u8fd8\u597d\uff0c\u5c31\u6015\u5f7c\u6b64\u8fd8\u8981\u901a\u4fe1\uff0c\u51fa\u73b0\u4e92\u76f8\u7b49\u5f85\u7684\u5c40\u9762\u3002

\n

\u7ebf\u7a0b\u5177\u6709 CPU \u4eb2\u548c\u6027\uff08\u4e00\u822c\u8bed\u8a00\u6765\u8bb2\uff09\u3002

\n

\u6bd4\u5982 Golang \u7684 M:N \u6a21\u578b\uff0c\u4e3b\u5f20 \u5148\u751f\u6210 M \u4e2a\u7ebf\u7a0b\uff0cM \u662f\u673a\u5668 CPU \u6838\u5fc3\u6570\uff0c\u7136\u540e\u518d\u5728 M \u4e2a\u7ebf\u7a0b\u4e4b\u95f4\u8c03\u5ea6\u5b9e\u9645\u4ea7\u751f\u7684 N \u4e2a\u4efb\u52a1\u3002

\n

\u6bd4\u5982 Nginx \u7684\u914d\u7f6e\u4e5f\u4e3b\u5f20 \u914d\u7f6e\u7ebf\u7a0b\u6838\u5fc3\u6570\u548c CPU \u6838\u5fc3\u6570\u4e00\u81f4\u3002

\n

\u4ec0\u4e48\u65f6\u5019\u7528\u7ebf\u7a0b\u3001\u4ec0\u4e48\u65f6\u5019\u7528\u534f\u7a0b\uff1f

\n

\u7ebf\u7a0b\u3001\u534f\u7a0b\u4ea7\u751f\u7684\u539f\u56e0\u662f\u4ec0\u4e48\uff1f

\n

\u5176\u5b9e\u8fd8\u662f\u4e3a\u4e86\u8c03\u5ea6\u3002

\n

\u7ebf\u7a0b\u662f\u7ec6\u5206\u8fdb\u7a0b\u4e0b\u5171\u4eab\u5185\u5b58\u7684\u573a\u666f\uff1b\u534f\u7a0b\u662f\u4e3a\u4e86\u7ec6\u5316\u8c03\u5ea6\u3002

\n

\u56e0\u4e3a\u8fdb\u7a0b\u3001\u7ebf\u7a0b\u672c\u8d28\u4e0a\u662f\u64cd\u4f5c\u7cfb\u7edf\u5728\u8c03\u5ea6\u3002\u64cd\u4f5c\u7cfb\u7edf\u5e76\u4e0d\u6e05\u695a\u4ec0\u4e48\u65f6\u5019\u5e94\u8be5\u8c03\u5ea6\u3002\u53ea\u80fd\u91c7\u7528\u5404\u79cd\u4f18\u5148\u8ba1\u7b97\u6cd5\u3001\u5e73\u5747\u7b97\u6cd5\u3002\u518d\u600e\u4e48\u7b97\uff0c\u4e5f\u662f\u76f2\u4eba\u6478\u8c61\u7f62\u4e86\u3002

\n

\u534f\u7a0b\u7ed9\u4e86\u7a0b\u5e8f\u5458\u4e00\u4e2a\u53e3\u5b50\uff0c\u4f60\u53ef\u4ee5\u7528 \u534f\u7a0b\u5728 \u6d89\u53ca\u963b\u585e\u90e8\u5206\u8fdb\u884c\u8ba9\u51fa\u63a7\u5236\u6743\u3002

\n

\u7b80\u800c\u8a00\u4e4b\uff0c\u7ecf\u9a8c\u4e4b\u8c08\uff1a

\n

\u6d89\u53ca\u5230 \u8ba1\u7b97\u5bc6\u96c6\u578b \u8bf7\u7528\u7ebf\u7a0b\u3002

\n

\u5982\u679c\u6d89\u53ca\u5230 IO \u963b\u585e\u5bc6\u96c6\uff0c\u8bf7\u7528\u534f\u7a0b\u3002

\n

\u6211\u4eec\u7684\u76ee\u7684\u4e0d\u662f\u4e3a\u4e86\u7528\u800c\u7528\uff0c\u800c\u662f\u4f7f\u7528\u8c03\u5ea6\uff0c\u63d0\u9ad8\u6211\u4eec\u4ee3\u7801\u6267\u884c\u7684\u6548\u7387\uff0c\u51cf\u5c11\u7b49\u5f85\u3002

\n

\u786c\u4ef6\u4e2d\u65ad

\n

\u5982\u679c\u8bf4\u5176\u5b9e\u6ca1\u6709 if-else\\switch\\while \uff0c\u8ba1\u7b97\u673a\u5668\u5176\u5b9e\u53ea\u6709 goto \u3002

\n

\u5982\u679c\u4f60\u770b\u8fc7\u6c47\u7f16\uff0c\u5927\u6982\u7406\u89e3\u6211\u662f\u4ec0\u4e48\u610f\u601d\u3002

\n

\u540c\u6837\uff0c\u8ba1\u7b97\u673a\u91cc\u8fdb\u7a0b\u3001\u7ebf\u7a0b\u3001\u534f\u7a0b\u80cc\u540e\u8c03\u5ea6\u7684\u79d8\u5bc6\uff0c\u90fd\u6765\u81ea\u4e8e CPU \u7684\u786c\u4ef6\u4e2d\u65ad\u529f\u80fd\u3002

\n

\u53ea\u4e0d\u8fc7\u662f\u4e0a\u4e0b\u6587\u5feb\u901f\u5207\u6362\uff0c\u5207\u6362\u4e0a\u4e0b\u6587\u591a\u548c\u5c11\u7f62\u4e86\u3002

\n

2048 \u7684\u5b9e\u73b0

\n

\u5176\u5b9e 2048 \u7684\u5173\u952e\u5c31\u662f\u76f8\u90bb\u5143\u7d20\u5408\u5e76\uff0c\u5b9e\u73b0\u8fd9\u4e48\u4e00\u4e2a\u7b97\u6cd5\uff0c\u53cd\u590d\u6267\u884c\u5230\u65e0\u5143\u7d20\u53ef\u4ee5\u7ee7\u7eed\u5408\u5e76\u3002\u518d\u628a\u8fd9\u4e2a\u5e94\u7528\u5230 x\\y \u65b9\u5411\u6240\u6709\u884c\u5217\u5c31\u597d\u4e86\u3002

\n

\u5177\u4f53\u7ebf\u7a0b

\n

\u76ee\u524d\u5b9e\u73b0\u6210\u901a\u8fc7\u961f\u5217\u6765\u5b9e\u73b0\u901a\u4fe1\uff1a

\n

IO \u7ebf\u7a0b\uff0c\u7528\u6237\u4ea7\u751f\u4e00\u4e2a\u8f93\u5165\uff0c\u8fdb\u5165\u4e8b\u4ef6\u961f\u5217\u3002\n\u6e38\u620f\u8bfb\u53d6\u4e8b\u4ef6\u961f\u5217\uff0c\u5f00\u59cb\u8ba1\u7b97\u6e38\u620f\u6570\u636e\uff0c\u628a\u7ed3\u679c\u585e\u5165\u6e32\u67d3\u961f\u5217\u3002\n\u6e32\u67d3\u7ebf\u7a0b\uff0c\u8bfb\u53d6\u6e32\u67d3\u961f\u5217\u6570\u636e\u8fdb\u884c\u6e32\u67d3\u3002

\n

\u540e\u7eed\u8ba8\u8bba

\n

\u6211\u548c\u540c\u4e8b\u4ea4\u6d41\u4e86\u4e00\u4e0b\uff0c\u5c31 2048 \u800c\u8a00\u5176\u5b9e\u53ef\u4ee5\u5f88\u591a\u65b9\u5f0f\u505a\uff1a

\n
    \n
  1. \u5982\u679c\u662f\u961f\u5217\u4f9d\u8d56\u5f0f
  2. \n
\n

\u6211\u4eec\u7b49\u4e8e\u505a\u51fa\u4e00\u4e2a pipline \u7684\u65b9\u5f0f\u4e86

\n
    \n
  1. \u6211\u4eec\u4e5f\u53ef\u4ee5\u89e3\u5f00\u961f\u5217\u963b\u585e
  2. \n
\n

\u771f\u6b63\u7684\u81ea\u7531\u6e32\u67d3\u3002\u867d\u7136 2048 \u770b\u4e0d\u51fa\u6548\u679c

\n

\u961f\u5217\u8ffd\u8d76\u95ee\u9898

\n

\u7528\u6237\u4e0d\u65ad\u5730\u6572\u51fb\uff0c\u4ea7\u751f\u65f6\u95f4\uff0c\u5982\u679c\u961f\u5217\u91cc\u4e00\u81f4\u4ea7\u751f\u6570\u636e\uff0c\u90a3\u4e0d\u662f\u6e32\u67d3\u6c38\u8fdc\u8ffd\u4e0d\u4e0a\uff1f

\n

\u591a\u7ebf\u7a0b\u961f\u5217\u9700\u8981\u601d\u8003 \u751f\u4ea7\u8005\u3001\u6d88\u8d39\u8005\u6a21\u578b\uff0c\u9700\u8981\u8bbe\u8ba1\u5339\u914d\u7684\u65b9\u5f0f\u3002

\n

\u89e3\u51b3\u65b9\u6cd5

\n

1 \uff09\u63a7\u5236\u751f\u4ea7\u9891\u7387\uff0c\u751f\u4ea7\u548c\u6d88\u8017\u76f8\u62b5\u6d88

\n

\u4e8b\u4ef6\u91c7\u6837\u3001\u6e32\u67d3 \u53ef\u4ee5\u4fdd\u6301\u4e00\u4e2a\u9891\u7387

\n

2 \uff09\u4e0d\u63a7\u5236\u751f\u4ea7\uff0c\u4f46\u662f\u8df3\u8fc7\u751f\u4ea7

\n

\u4e8b\u4ef6\u91c7\u6837\uff0c\u53ef\u4ee5\u643a\u5e26\u65f6\u95f4\u6233\u3002

\n

\u5982\u679c\u6e32\u67d3\u7684\u65f6\u5019\uff0c\u6bcf\u6b21\u65f6\u95f4\u8d85\u65f6\uff0c\u8df3\u8fc7\u5173\u952e\u5e27\u3002

\n

\u5f53\u7136\u8fd9\u4e9b\u90fd\u662f\u5f88\u7ec6\u5316\u7684\u95ee\u9898\u4e86\u3002

\n

\u603b\u7ed3

\n

\u6211\u503e\u5411\u4e8e\u7814\u7a76\u4e00\u4e2a\u4e1c\u897f\uff0c\u601d\u8003\u4ed6\u7684\u5168\u90e8\uff0c\u5bfb\u627e\u6700\u4f73\u7684\u8def\u5f84\u3002\n\u8fd9\u4e9b\u90fd\u662f\u6478\u9c7c\u7ed3\u679c\uff0c\u7b80\u5355\u5206\u4eab\u4e0b\u3002\u66f4\u6df1\u7684\u611f\u53d7\u8fd8\u9700\u8981\u5b9e\u8df5\u548c\u4ea4\u6d41\u3002

\n

\u540e\u7eed

\n

\u4e0a\u6587\u63d0\u5230\u6e38\u620f\u91cc\u9762\u6700\u65b0\u6d41\u884c ECS \u67b6\u6784\u3002ECS \u629b\u5f03\u4e86\u9762\u5411\u5bf9\u8c61\u7684\u601d\u60f3\uff0c\u628a\u540c\u7c7b\u6570\u636e\u6446\u653e\u5728\u4e00\u8d77\uff0c\u4eb2\u548c CPU \u8fd0\u884c\u673a\u5236\uff0c\u65b9\u4fbf\u5927\u89c4\u6a21\u5c5e\u6027\u904d\u5386\u3002

\n

ECS \u5e94\u8be5\u5982\u4f55\u7528 Ruby \u5b9e\u73b0\u5462\uff1f

\n

\u6211\u7684\u535a\u5ba2

\n" }, { "author": { "url": "member/Mark24", "name": "Mark24", "avatar": "https://cdn.v2ex.com/avatar/edea/c9b0/62847_large.png?m=1723538556" }, "url": "t/868255", "title": "\u7528 Ruby \u8bb2\u4ece\u521b\u4e1a\u5230 996 \u516c\u53f8\u7684\u6545\u4e8b(\u620f\u8bf4 master-worker \u6a21\u5f0f)", "id": "t/868255", "date_published": "2022-07-23T13:31:33+00:00", "content_html": "

\u524d\u8a00

\n

\u9605\u8bfb\u5927\u6982\u9700\u8981 20 \u5206\u949f\u3002

\n

\u5047\u8bbe\u4f60\u5e0c\u671b\u4e86\u89e3 \u7ebf\u7a0b\u3001\u7ebf\u7a0b\u6c60\u3001\u96c6\u7fa4\u6a21\u5f0f /Master-Worker \u6a21\u5f0f\u3001\u8c03\u5ea6\u5668\u3002

\n

\u9700\u8981\u4e86\u89e3 Ruby \u57fa\u672c\u7684\u7528\u6cd5\u548c\u9762\u5411\u5bf9\u8c61\u601d\u60f3\u3002

\n

\u672c\u6587\u620f\u8bf4\uff0c\u65e0\u987b\u4e25\u8083\u5bf9\u5f85\u3002\u52ff\u5bf9\u53f7\u5165\u5ea7\u3002\u4e2a\u4eba\u4e5f\u6ca1\u6709\u4e25\u8083\u89c2\u70b9\u3002\u4e2a\u4eba\u89c2\u70b9\u548c\u6240\u6709\u4eba\u6ca1\u6709\u5173\u7cfb\u3002

\n

\u672c\u6587\u535a\u5ba2\u5730\u5740

\n

\u5b8c\u6574\u4ee3\u7801\u793a\u4f8b

\n

github:rb-master-worker-demo

\n

Master Worker \u6a21\u5f0f

\n

MasterWorker \u6a21\u5f0f\uff0c\u4e5f\u6709\u7ffb\u8bd1\u6210\u4f5c\u96c6\u7fa4\u6a21\u5f0f\u3001\u4e5f\u53eb Master-Slave \u6a21\u5f0f\u3002

\n
\n

Git \u4e0d\u8bb8\u4f7f\u7528 master \u4e86\uff0c\u6362\u6210\u4e86 main \uff0cMaster/Slave \u5177\u6709\u653f\u6cbb\u4e0d\u6b63\u786e\u7684\u6b67\u89c6\u8272\u5f69\u3002\u4e0d\u8fc7\u8fd9\u4e0d\u91cd\u8981\u4e86\u3002\u5176\u5b9e\u8fd9\u4e2a\u540d\u5b57\u5f88\u80fd\u8868\u8fbe\u8fd9\u4e2a\u6a21\u5f0f\u7684\u7279\u70b9\u3002

\n
\n

\u4e3b\u8981\u601d\u60f3\u5c31\u662f\u7531\u4e00\u4e2a Master \u62bd\u8c61\u5bf9\u8c61\u6765\u8c03\u5ea6 Worker \u5bf9\u8c61\u6765\u5de5\u4f5c\u3002

\n

Ruby \u6587\u5b66\u7f16\u7a0b\uff0c\u7528\u4ee3\u7801\u8bb2\u6545\u4e8b

\n

\u5176\u5b9e\u8fd9\u4e5f\u975e\u5e38\u50cf\u73b0\u5b9e\u4e2d\u7684\u5de5\u4f5c\u6a21\u578b\u3002Ruby \u5929\u751f\u9762\u5411\u5bf9\u8c61\uff0c\u8868\u8fbe\u7684\u6587\u5b66\u6027\uff0c\u6211\u4eec\u53ef\u4ee5\u5f88\u65b9\u4fbf\u7684\u6765\u4f7f\u7528\u4ee3\u7801\u6a21\u62df\u8fd9\u79cd\u73b0\u5b9e\u60c5\u51b5\u3002\n\u6211\u4eec\u6765\u7528 Ruby \u6a21\u62df\u4e0b\u73b0\u5b9e\u4e2d\u8fd9\u79cd\u60c5\u51b5\uff0c\u987a\u4fbf\u5b66\u4e0b\u5982\u4f55\u5b9e\u73b0\u8fd9\u4e2a\u6a21\u5f0f\u3002

\n

\u7ea6\u5b9a

\n

\u4f1a\u51fa\u73b0\u51e0\u4e2a\u7c7b\uff1a

\n\n

\u6545\u4e8b\u7684\u601d\u8def\uff1a

\n

\u6211\u4eec\u81ea\u5df1\u662f\u5ba2\u6237\uff0c\u628a\u201c\u4efb\u52a1\u201d\u8ba2\u5355\u4ea4\u7ed9\u201c\u516c\u53f8\u201d\uff0c\u8fd9\u4e9b\u4efb\u52a1\u4f1a\u8f6c\u4ea4\u7ed9\u201c\u9886\u5bfc\u201d\u624b\u4e2d\uff0c\u7136\u540e\u201c\u9886\u5bfc\u201d\u4f1a\u6392\u671f\uff0c\u628a\u5de5\u4f5c\u5e03\u7f6e\u7ed9\u201c\u6253\u5de5\u4eba\u201d\u3002\u6700\u7ec8\u201c\u6253\u5de5\u4eba\u201d\u4e50\u6b64\u4e0d\u75b2\u7684\u5b8c\u6210\u4efb\u52a1\u3002

\n

\u5b9e\u73b0 \u6253\u5de5\u4eba Worker \u7c7b

\n

step1 \u7ed9\u5458\u5de5\u5de5\u53f7

\n

\u9996\u5148\u6211\u4eec\u5efa\u7acb\u4e00\u4e2a Worker \u7c7b\uff0c\u6211\u4eec\u7ed9\u4ed6\u4e00\u4e2a\u540d\u5b57\u5c5e\u6027\u3002attr \u66b4\u9732\u51fa name \u5c5e\u6027\u3002

\n
# Workshop.rb\n\nclass Worker\n attr :name\n def initialize(name)\n @name = \"worker@#{name}\"\n end\nend\n
\n

\u6211\u4eec\u91c7\u7528 TDD \u65b9\u5f0f\u6765\u9010\u6b65\u5b9e\u73b0\u6211\u4eec\u7684\u60f3\u6cd5\uff1a

\n
#Workshop_test.rb\nrequire 'minitest/autorun'\nrequire_relative '../lib/Workshop'\n\ndescribe Worker do\n it \"check worker name\" do\n w = Worker.new(\"ruby01\")\n assert_equal w.name, \"worker@ruby01\"\n end\nend\n
\n

\u5f88\u5feb\uff0c\u6211\u4eec\u77e5\u9053\u8fd9\u540d\u6253\u5de5\u4eba\u4ed6\u53eb \u201cruby01\u201d \u5458\u5de5\u3002

\n

step2 \u7ed9\u5458\u5de5 KPI/OKR

\n

\u6211\u4eec\u4e0d\u5e0c\u671b\u6253\u5de5\u4eba\u6bcf\u6b21\u53ea\u80fd\u505a\u4e00\u4ef6\u4e8b\uff0c\u4f60\u5fc5\u987b\u5f97\u63a8\u7740\u4ed6\u624d\u80fd\u5de5\u4f5c\u3002\u4ed6\u6700\u597d\u5b66\u4f1a\u201c\u6210\u957f\u201d\u4f1a\u81ea\u5df1\u52aa\u529b\u7684\u5de5\u4f5c\u3002\n\u5176\u5b9e\u5c31\u662f\u4e00\u5806\u4efb\u52a1\uff0c\u6211\u4eec\u5e0c\u671b\u4ed6\u4eec\u4e00\u76f4\u5fd9\u3002\u7ed9\u4ed6 N \u4ef6\u4e8b\u60c5\uff0c\u4ed6\u4e00\u4e2a\u4e00\u4e2a\u81ea\u5df1\u505a\u3002\n\u6211\u4eec\u8981\u7ed9\u4ed6\u4e00\u4e2a\u76ee\u6807\uff0c\u4e5f\u5c31\u662f KPI \u6216\u8005 OKR \u968f\u4fbf\u5427\uff0c\u5b9e\u9645\u4e0a\u8fd9\u662f\u4e00\u4e2a\u961f\u5217\u5bf9\u5427\u3002\u6211\u4eec\u7528\u961f\u5217\u5b9e\u73b0\u3002

\n
require 'thread'\n\nclass Worker\n attr :name\n def initialize(name)\n @name = \"worker@#{name}\"\n @queue = Queue.new\n @thr = Thread.new { perfom }\n end\n\n def <<(job)\n @queue.push(job)\n end\n\n def join\n @thr.join\n end\n\n def perfom\n while (job = @queue.deq)\n break if job == :done\n puts \"worker@#{name}: job:#{job}\"\n job.call\n end\n end\n\n def size\n @queue.size\n end\nend\n
\n

\u73b0\u5728\u6253\u5de5\u4eba\u53d8\u5f97\u5145\u5b9e\u4e86\u8bb8\u591a\uff0c\u4ed6\u81ea\u4ece\u6765\u4e86\u516c\u53f8\u57f9\u8bad\u4e4b\u540e\uff0c\u5c31\u62e5\u6709\u4e86\u5f88\u591a\u5c5e\u6027\u548c\u65b9\u6cd5\u3002

\n\n

@queue \u5c31\u662f\u4ed6\u7684 OKR \u6e05\u5355\uff0c\u4ed6\u5fc5\u987b\u5b8c\u6210\u6240\u6709\u7684\u5de5\u4f5c\u4efb\u52a1\u3002

\n

@thr \u610f\u601d\u662f thread \u7f29\u5199\uff0c\u8fd9\u91cc\u662f\u4f1a\u4f7f\u7528\u4e00\u4e2a\u7ebf\u7a0b\u6765\u8c03\u7528 perform \u6211\u4eec\u5728\u7528\u7ebf\u7a0b\u6a21\u62df\u6253\u5de5\u4eba\u5e72\u6d3b\u8fd9\u4ef6\u4e8b\u3002\u53ef\u4ee5\u7406\u89e3\u4e3a @thr \u5c31\u662f\u6253\u5de5\u4eba\u7684\u7075\u9b42\u3002

\n\n

<< \u662f\u4e00\u4e2a push \u65b9\u6cd5\u7684\u8bed\u6cd5\u7cd6\uff0c\u5c31\u7ed9\u7ed9\u81ea\u5df1\u7684 OKR \u91cc\u6dfb\u52a0\u4efb\u52a1\u3002

\n

perform\n\u53ef\u80fd\u8981\u8bf4\u4e0b perform \u65b9\u6cd5, \u8fd9\u91cc\u662f \u201c\u8fd0\u884c\u201d\u7684\u610f\u601d\u54c8\uff0c\u4e0d\u662f\u201c\u8868\u6f14\u201d :P \u3002\n\u6253\u5de5\u4eba\u600e\u4e48\u5e72\u6d3b\u5462\uff1f\u8fd9\u5f97\u8bf4\u9053\u8bf4\u9053\u3002\u6211\u4eec\u5f97\u6307\u5bfc\u4ed6\u5982\u4f55\u201c\u6210\u957f\u201d\u3002

\n

\u6211\u4eec\u524d\u9762\u8bf4\u4e86 @queue \u5c31\u662f\u4ed6\u7684 OKR, \u4ed6\u5fc5\u987b\u4ece\u81ea\u5df1\u7684 OKR \u4e2d\u53d6\u51fa\u4efb\u52a1\u7136\u540e\u6267\u884c\u3002\u8fd9\u91cc\u6211\u7528\u4e86 job.call\u3002\n\u6697\u793a\uff0c\u8fd9\u5fc5\u987b\u662f\u4e00\u4e2a callable \u5bf9\u8c61\uff0c\u5728 ruby \u91cc\u4e5f\u5c31\u662f\u62e5\u6709 call \u65b9\u6cd5\u7684\u5bf9\u8c61\u3002\u53ef\u4ee5\u662f lambda \u3001\u6216\u8005\u5b9e\u73b0 call \u7684\u3002\n\u8fd9\u4e5f\u5f88\u5408\u7406\uff0c\u9700\u6c42\u5fc5\u987b\u80fd\u505a\u624d\u4f1a\u505a\u3002\u6ca1\u6cd5\u505a\u7684\u9700\u6c42\uff0c\u505a\u4e0d\u4e86\u5c31\u662f\u505a\u4e0d\u4e86\u3002

\n

\u4f46\u662f\u5982\u679c\u7ed9\u4e86\u4e00\u4e2a :done \u53e6\u8bf4\u3002\u5faa\u73af\u4f1a\u7ed3\u675f\uff0c\u8fd9\u4e2a\u7ebf\u7a0b\u4f1a\u6d88\u5931\u3002(\u88c1\u5458\u4e86 :P)

\n
 def perfom\n while (job = @queue.deq)\n break if job == :done\n puts \"worker@#{name}: job:#{job}\"\n job.call\n end\n end\n
\n
\n

\u5176\u5b9e Queue \u8fd9\u4e2a\u5bf9\u8c61\u5f88\u6709\u610f\u601d\uff0cRuby \u505a\u4e86\u4e00\u4e9b\u5de5\u4f5c\u3002Queue \u5728\u7a7a\u7684\u65f6\u5019\uff0c\u865a\u62df\u673a\u4f1a\u8ba9\u7ebf\u7a0b\u8fdb\u5165\u7761\u7720\u7b49\u5f85\u3002\u5982\u679c\u961f\u5217\u91cc\u6709\u4efb\u52a1\uff0c\u5c31\u4f1a\u7ee7\u7eed\u5de5\u4f5c\u3002Ruby \u5f88\u8d34\u5fc3\uff0c\u679c\u7136\u662f\u7a0b\u5e8f\u5458\u7684\u597d\u670b\u53cb\u554a\u3002 \u5176\u5b9e\u6211\u4e0d\u77e5\u9053\u5176\u4ed6\u8bed\u8a00\u4ec0\u4e48\u6837\uff0c\u61d2\u5f97\u67e5\u4e86\u3002

\n
\n

join \u65b9\u6cd5\u662f\u4e00\u4e2a Thread \u7684\u7ebf\u7a0b\u65b9\u6cd5\uff0c\u4e3b\u8981\u7684\u4f5c\u7528\u662f\u544a\u8bc9\u4e3b\u7ebf\u7a0b\u4f60\u8981\u7b49\u5f85\u6bcf\u4e00\u4e2a\u5b50\u7ebf\u7a0b\uff08\u81ea\u5df1\uff09\u7684\u5b8c\u6210\u3002\u5982\u679c\u4e0d\u5199\u8fd9\u53e5\uff0c\u4e3b\u7ebf\u7a0b\u5982\u679c\u6bd4\u6240\u6709\u5b50\u7ebf\u7a0b\u63d0\u524d\u7ed3\u675f\u3002\u90a3\u4e48\u5b50\u7ebf\u7a0b\u4f1a\u88ab\u5168\u90e8\u5173\u95ed\u3002\u7b80\u800c\u8a00\u4e4b join \u5c31\u662f\u540c\u6b65\u7b49\u5f85\u7ebf\u7a0b\u7ed3\u679c\u3002

\n

\u8ba9\u6211\u4eec\u6765\u770b\u770b TDD:

\n

\u6211\u4eec\u53ef\u4ee5\u52a0\u4e00\u6bb5\u9a8c\u8bc1\u5de5\u53f7 ruby02 \u7684\u6253\u5de5\u4eba\u662f\u4e0d\u662f\u5982\u671f\u7684\u5b8c\u6210\u4e86\u5de5\u4f5c\u3002

\n
# ....\n it \"check worekr do sth job\" do\n w = Worker.new(\"ruby02\")\n\n finished = []\n w << lambda { puts \"do job 1\"; finished.push \"job1\"}\n w << lambda { puts \"do job 2\"; finished.push \"job2\"}\n w << :done\n w.join\n\n assert_equal finished, [\"job1\",\"job2\"]\n end\n\n# ....\n
\n

\u5176\u5b9e\u5230\u8fd9\u91cc\uff0c\u4e00\u4e2a\u5408\u683c\u7684\u6253\u5de5\u4eba\u5c31\u6253\u9020\u5b8c\u6bd5\u4e86\u3002\u6253\u5de5\u4eba\u5f88\u7b80\u5355\uff0c\u53ea\u8981\u5403\u82e6\u8010\u52b3\uff0c\u4e00\u5207\u90fd OK \u3002\n\u4e0b\u9762\u6211\u4eec\u8981\u5b9e\u73b0\u4e0b Workshop \u516c\u53f8\u7c7b\u3002

\n

\u5b9e\u73b0 \u516c\u53f8 Workshop \u7c7b

\n

\u5728\u6b64\u4e4b\u524d\uff0c\u6211\u4eec\u5148\u5b9e\u73b0\uff1a\u521b\u4e1a\u516c\u53f8 MiniWorkshop \u7c7b

\n

\u5176\u5b9e\u6211\u6253\u7b97\u8fc7\u6e21\u4e0b\uff0c\u9996\u5148\u5b9e\u73b0\u4e00\u4e2a \u201c\u521b\u4e1a\u516c\u53f8\u201d MiniWorkshop\u3002\n\u521b\u4e1a\u516c\u53f8\u521a\u8d77\u6b65\uff0c\u4e00\u822c\u662f\u53ea\u6709\u201c\u6253\u5de5\u4eba\u201d\uff0c\u6ca1\u6709\u771f\u6b63\u610f\u4e49\u4e0a\u7684\u4e2d\u5c42\u51fa\u73b0\u3002\n\u8fd9\u4e00\u65f6\u671f\u975e\u5e38\u7b80\u5355\uff0c\u4f0a\u7538\u56ed\u65f6\u671f\u3002\u6709\u6d3b\u5927\u5bb6\u4e00\u8d77\u5e72\uff0c\u5927\u5bb6\u90fd\u662f\u5144\u5f1f\u3002

\n
class MiniWorkshop\n def initialize(count)\n @worker_count = count # \u6253\u5de5\u4eba\u6570\u91cf\n @workers = @worker_count.times.map do |i| # \u6839\u636e\u6570\u91cf\u751f\u6210(\u62db\u8058)\u6253\u5de5\u4eba\n Worker.new(i) # \u7ed9\u4e2a\u5de5\u53f7\n end\n end\n\n # \u521d\u521b\u516c\u53f8\u5206\u914d\u4efb\u52a1\n def <<(job)\n if job == :done\n @workers.map {|m| m << job}\n else\n # \u968f\u673a\u9009\u62e9\u4e00\u4e2a\u6253\u5de5\u4eba\uff0c\u63a5\u6d3b\n @workers.sample << job\n end\n end\n\n def join\n @workers.map {|m| m.join}\n end\nend\n
\n

\u8fd9\u91cc\u53ef\u80fd\u8bf4\u4e0b

\n
 def <<(job)\n if job == :done\n @workers.map {|m| m << job}\n else\n # \u968f\u673a\u9009\u62e9\u4e00\u4e2a\u6253\u5de5\u4eba\uff0c\u63a5\u6d3b\n @workers.sample << job\n end\n end\n
\n

\u8fd9\u91cc\u5e72\u6d3b\u7684\u6a21\u5f0f\u53ef\u80fd\u4e0d\u597d\uff0c\u56e0\u4e3a\u6211\u4eec\u7adf\u7136 Array#sample \u65b9\u5f0f\u3002\u8fd9\u662f\u4e00\u4e2a\u968f\u673a\u65b9\u6cd5\u3002\u968f\u673a\u9009\u62e9\u4e00\u4e2a\u3002\n\u770b\u4f3c\u4e0d\u5408\u7406\uff0c\u5b9e\u9645\u4e0a\u4e5f\u5408\u60c5\u5408\u7406\u3002

\n

\u521b\u4e1a\u516c\u53f8\u521d\u671f\u867d\u7136\u662f\u8349\u6839\uff0c\u53ef\u662f\u5927\u5bb6\u54ea\u4e2a\u4e0d\u662f\u5927\u4f6c\u3002\u6240\u4ee5\u6d3b\u6765\u4e86\u8c01\u90fd\u884c\uff0c\u95ee\u9898\u4e0d\u5927\u3002

\n

\u6ca1\u4e8b\u6211\u4eec\u540e\u9762\u518d\u6539\u8fdb\u597d\u4e86\u3002

\n

TDD:

\n

\u6211\u4eec\u7684\u5355\u5143\u6d4b\u8bd5\u5176\u5b9e\u63cf\u8ff0\u4e86\u4e00\u4e2a\u6545\u4e8b\u3002\u4e00\u5bb6\u521b\u4e1a\u516c\u53f8\uff0c\u53ea\u6709 2 \u4e2a\u4eba\u3002\u63a5\u5230\u4e86\u4e00\u4e2a\u8ba2\u5355\u662f 4 \u4e2a\u5de5\u4f5c\u5185\u5bb9\u3002

\n
# ...\n it \"check MiniWorkshop work\" do\n ws = MiniWorkshop.new(2)\n\n finished = []\n ws << lambda { puts \"job1\"; finished.push \"job1\"}\n ws << lambda { puts \"job2\"; finished.push \"job2\"}\n ws << lambda { puts \"job3\"; finished.push \"job3\"}\n ws << lambda { puts \"job4\"; finished.push \"job4\"}\n ws << :done\n\n ws.join\n\n assert_equal finished.size, 4\n end\n# ...\n
\n

\u6211\u4eec\u56de\u8fc7\u5934\u518d\u770b MiniWorkshop \u7c7b\uff0c\u521d\u59cb\u5316\u7684\u65f6\u5019\u521b\u5efa\u4e86\u4e24\u4e2a\u5458\u5de5\u3002\u4efb\u52a1\u6765\u4e86\u5c31\u968f\u673a\u5206\u914d\u7ed9\u4e00\u4e2a\u5458\u5de5\u3002\n\u5f88\u7b26\u5408\u5c0f\u4f5c\u574a\u7684\u6a21\u5f0f\u3002

\n

\u5b9e\u73b0\u4e0a\u5e02\u516c\u53f8

\n

\u516c\u53f8\u53d8\u5927\u4e86\uff0c\u5c31\u4e0d\u6b62 2 \u4e2a\u5458\u5de5\u4e86\u3002\u53ef\u80fd\u56db\u4e94\u767e\u53f7\uff0c\u968f\u673a\u4ea4\u7ed9\u4e00\u4e2a\u5458\u5de5\uff0c\u4e0d\u73b0\u5b9e\u3002\u4e2d\u5c42\u7ba1\u7406\u51fa\u73b0\u3002\u4e2d\u5c42\u51fa\u73b0\u610f\u5473\u7740\u6211\u4eec\u516c\u53f8\u7684\u7c7b\u4e5f\u8981\u8fdb\u884c\u6539\u53d8\uff0c\u516c\u53f8\u9700\u8981\u6539\u9769\u3002

\n

\u6211\u4eec\u5148\u5b9e\u73b0\u4e00\u4e2a\u6539\u9769\u4e4b\u540e\u7684 Workshop \u516c\u53f8\u7c7b\u3002

\n
class Workshop\n def initialize(count, master_name)\n @worker_count = count\n @workers = @worker_count.times.map do |i|\n Worker.new(i)\n end\n @master = Master.new(@workers) # \u65b0\u589e\u89d2\u8272\n end\n\n def <<(job)\n if job == :done\n @workers.map {|m| m << job}\n else\n @master.assign(job) # master \u5206\u914d\u4efb\u52a1\n end\n end\n\n def join\n @workers.map {|m| m.join}\n end\nend\n
\n

\u53ef\u4ee5\u770b\u5230\uff0c\u6211\u4eec\u5728\u521d\u59cb\u5316\u51fd\u6570\u91cc\u65b0\u589e\u4e86 @master \u4ed6\u63a5\u53d7 @workers \u4f5c\u4e3a\u53c2\u6570\u3002\u6bd5\u7adf\u9886\u5bfc\u8981\u70b9\u5175\u554a\u3002

\n

<<\u65b9\u6cd5\u4e5f\u8fdb\u884c\u4e86\u6539\u8fdb\uff0c\u7531\u4ee5\u524d\u7684 \u76f4\u63a5\u8ba9 @workers \u63a5\u6536\u4efb\u52a1\uff0c\u53d8\u6210 @master.assign \u5206\u914d\u4efb\u52a1\u3002

\n

\u8ba9\u6211\u4eec\u6765\u770b\u4e0b Master \u7c7b

\n
class Master\n def initialize(workers)\n @workers = workers\n end\n\n def assign(job)\n @workers.sort{|a,b| a.size <=> b.size}.first << job\n end\nend\n
\n

\u5176\u5b9e\u4e5f\u4e0d\u590d\u6742\u3002\u6211\u4eec\u4fdd\u6301\u4e86 @workers \u7684\u6307\u9488\uff0c assign \u65b9\u6cd5\u66f4\u50cf\u662f\u628a\u4ee5\u524d\u5206\u914d\u7684\u903b\u8f91\u63a5\u8fc7\u6765\u5b9e\u73b0\u4e86\u4e00\u904d\u3002

\n

\u8fd9\u6b21\u6211\u4eec\u6539\u4e86\u5206\u914d\u4efb\u52a1\u7684\u65b9\u5f0f\uff0c\u6211\u4eec\u8981\u6839\u636e Worker#size \u5fd9\u788c\u7a0b\u5ea6\u6765\u5206\u914d\u4efb\u52a1\u3002

\n

\u6bd5\u7adf\u561b\uff0c\u9886\u5bfc\u6709\u4e2a\u65b9\u6cd5\u8bba\uff0c\u4f1a\u6bd4\u5c0f\u4f5c\u574a\u9ad8\u7ea7\u5f88\u591a\u3002

\n

\u591a\u91cd\u9886\u5bfc

\n

\u4e00\u4e2a\u9886\u5bfc\u5c31\u8db3\u591f\u4e86\u4e48\uff1f\u4e0d\u3002

\n

\u73b0\u5b9e\u4e2d\u6211\u4eec\u89c1\u8fc7\u5f62\u5f62\u8272\u8272\u7684\u9886\u5bfc\uff0c\u6709\u7684\u662f\u81ea\u5df1\u57f9\u517b\uff0c\u6709\u7684\u662f\u7559\u8fc7\u6d0b\uff0c\u6709\u7684\u662f\u5927\u5382\u7a7a\u964d\u3002\u4ed6\u4eec\u62e5\u6709\u4e0d\u540c\u7684\u201c\u65b9\u6cd5\u8bba\u201d\uff0c\u4e5f\u5c31\u662f Master#assign \u7684\u65b9\u5f0f\u53ef\u80fd\u4e0d\u540c\u3002

\n

\u6211\u4eec\u7ed9\u516c\u53f8\u518d\u52a0\u4e24\u4e2a\u9886\u5bfc\u3002

\n

\u65e0\u9650\u65b9\u6cd5\u8bba

\n

996ICU \u9886\u5bfc\uff1a

\n

\u6211\u4eec\u4f7f\u7528\u4e86 Array#cycle \u7684\u65b9\u5f0f\uff0c\u8fd9\u662f\u4e00\u4e2a\u8fed\u4ee3\u5668\u3002\u6bd4\u5982 [1,2,3].cycle \u6bcf\u6b21 .next \u4f1a\u4ea7\u751f 1 \u30012 \u30013 \u30011 \u30012 \u30013 \u30011 \u30012 \u30013 ..... \u65e0\u9650\u8f6e\u8bad\u3002

\n

\u8fd9\u4e2a\u65b9\u6cd5\u8bba\u5c31\u662f 996 \u65b9\u6cd5\u8bba\uff0c\u53ea\u8981\u5e72\u4e0d\u6b7b\u5c31\u5f80\u6b7b\u91cc\u5e72\u3002\u4eba\u6d77\u6218\u672f\uff0c\u628a\u4eba\u8f6e\u756a\u586b\u4e0a\u3002

\n
class ICU996Master\n def initialize(workers)\n @current_worker = workers.cycle # \u8fed\u4ee3\u5668\n end\n\n def assign(job)\n @current_worker.next << job\n end\nend\n
\n

\u5206\u7ec4\u4efb\u52a1\u65b9\u6cd5\u8bba

\n

\u7b49\u6211\u4eec\u7684\u516c\u53f8\u53d8\u5927\u4e86\uff0c\u6211\u4eec\u7684\u4e1a\u52a1\u4e5f\u4f1a\u53d8\u5f97\u4e30\u5bcc\uff0c\u4efb\u52a1\u4e0d\u662f\u90a3\u4e48\u5355\u4e00\u3002\u5f88\u591a\u5de5\u4f5c\u8981\u6dfb\u52a0\u4e0a\u7ec4\u522b group_id \uff0c\u5206\u95e8\u522b\u7c7b\u7684\u4ea4\u7ed9\u4e0d\u540c\u5de5\u79cd\u7684\u6253\u5de5\u4eba\uff0c\u6bd4\u5982 \u5f00\u53d1\u3001\u4ea7\u54c1\u3001\u6d4b\u8bd5\u3001\u8bbe\u8ba1\u3001\u8fd0\u8425\u3002

\n
\nclass GroupMaster\n GROUPS = [:group1, :group2, :group3]\n\n def initialize(workers)\n @workers = {}\n workers_per_group = workers.length / GROUPS.size\n workers.each_slice(workers_per_group).each_with_index do |slice, index|\n group_id = GROUPS[index]\n @workers[group_id] = slice\n end\n end\n\n def assign(job)\n worker = @workers[job.group].sort_by(&:size).first\n worker << job\n end\nend\n
\n

\u7136\u540e\u6211\u4eec\u53ef\u4ee5\u628a\u4e0d\u540c\u98ce\u683c\u7684\u9886\u5bfc\u73ed\u5b50\u96c6\u4e2d\u8d77\u6765

\n
Masters = {\n normal: NormalMaster,\n ICU996: ICU996Master,\n group: GroupMaster\n}\n
\n

\u6211\u4eec\u6539\u9020\u4e0b Workshop \u6bd5\u7adf\u8fd9\u4e2a\u8bcd\u662f\u4e00\u4e2a \u5de5\u4f5c\u5ba4\u7684\u610f\u601d\uff0c\u5176\u5b9e\u662f\u4e2a\u5c0f\u90e8\u95e8\u3002

\n

\u6211\u4eec\u6539\u9020\u4e4b\u540e\uff0c\u6211\u4eec\u7684\u5c0f\u90e8\u95e8\u53ef\u4ee5\u6309\u7167\u98ce\u683c\u4e0d\u540c\u7684\u9886\u5bfc\u8fdb\u884c\u5206\u6d3e\u5de5\u4f5c\u3002

\n
class Workshop\n def initialize(count, master_name) # \u65b0\u589e master_name \u6307\u5b9a\n @worker_count = count\n @workers = @worker_count.times.map do |i|\n Worker.new(i)\n end\n # \u5339\u914d master\n @master = Masters[master_name].new(@workers)\n end\n\n def <<(job)\n if job == :done\n @workers.map {|m| m << job}\n else\n @master.assign(job)\n end\n end\n\n def join\n @workers.map {|m| m.join}\n end\nend\n
\n

\u6211\u4eec\u6765\u770b\u770b\u4e0d\u540c\u90e8\u95e8\u7684 TDD

\n
 it \"check Workshop@ normal master\" do\n ws = Workshop.new(4, :normal)\n\n finished = []\n ws << lambda { puts \"job1\"; finished.push \"job1\"}\n ws << lambda { puts \"job2\"; finished.push \"job2\"}\n ws << lambda { puts \"job3\"; finished.push \"job3\"}\n ws << lambda { puts \"job4\"; finished.push \"job4\"}\n ws << :done\n\n ws.join\n\n assert_equal finished.size, 4\n end\n\n it \"check Workshop@ ICU996 master\" do\n ws = Workshop.new(4, :ICU996)\n\n finished = []\n ws << lambda { puts \"job1\"; finished.push \"job1\"}\n ws << lambda { puts \"job2\"; finished.push \"job2\"}\n ws << lambda { puts \"job3\"; finished.push \"job3\"}\n ws << lambda { puts \"job4\"; finished.push \"job4\"}\n ws << :done\n\n ws.join\n\n assert_equal finished.size, 4\n end\n\n it \"check Workshop@ group master\" do\n ws = Workshop.new(4, :group)\n\n class GroupJob\n def initialize(group_id, &b)\n @group_id = group_id\n @blk = b\n end\n\n # \u4efb\u52a1\u5206\u7ec4\n def group\n \"group#{@group_id}\".to_sym\n end\n\n def call\n\n @blk.call(@group_id)\n end\n end\n\n finished = []\n ws << GroupJob.new(1) { |group_id| finished.push(group_id)}\n ws << GroupJob.new(2) { |group_id| finished.push(group_id)}\n ws << GroupJob.new(3) { |group_id| finished.push(group_id)}\n ws << GroupJob.new(1) { |group_id| finished.push(group_id)}\n ws << :done\n\n ws.join\n\n assert_equal finished.size, 4\n end\n\n
\n

\u603b\u7ed3 Master-Worker \u6a21\u5f0f

\n

\u597d\u5427\uff0c\u620f\u8bf4\u4e0d\u662f\u80e1\u8bf4\uff0c\u6539\u7f16\u4e0d\u662f\u4e71\u7f16\u3002

\n

\u6211\u4eec\u4ece\u73b0\u5b9e\u7684\u6545\u4e8b\u4e2d\u8d70\u51fa\u6765\u3002

\n\n

\u5176\u5b9e\u5728\u8fd9\u91cc Master \u7c7b\uff0c\u53ef\u80fd\u4f1a\u88ab\u53eb\u505a Scheduler \u5373\u8c03\u5ea6\u5668\u3002\u5185\u90e8\u7684\u65b9\u6cd5\u4e3b\u8981\u662f\u4f7f\u7528\u4e0d\u540c\u7684\u7b56\u7565\u6765\u5206\u914d\u4efb\u52a1\u3002

\n

\u800c\u4e0d\u540c\u7684 Master \u5b9e\u73b0\u7684 assign \u65b9\u6cd5\u5c31\u662f \u8c03\u5ea6\u7b56\u7565\u3002

\n\n

Workshop \u5176\u5b9e \u6301\u6709 @workers\uff0c\u4e5f\u5c31\u662f\u8bf4\u6c47\u805a\u4e86\u5b9e\u9645\u5de5\u4f5c\u7ebf\u7a0b\u7684\u5bf9\u8c61\u3002\u4ed6\u4eec\u53ef\u80fd\u4f1a\u6709\u53e6\u4e00\u4e2a\u540d\u5b57 \u2014\u2014 \u7ebf\u7a0b\u6c60\uff08 Thread Pool)

\n

\u6545\u4e8b\u8bb2\u5b8c\u4e86\uff0c\u4f60\u6709\u6ca1\u6709\u5b66\u4f1a\u5462\uff1f :D

\n

\u793a\u4f8b\u4ee3\u7801\uff1a

\n\n

\u53c2\u8003\u8d44\u6599\uff1a

\n\n" }, { "author": { "url": "member/Mark24", "name": "Mark24", "avatar": "https://cdn.v2ex.com/avatar/edea/c9b0/62847_large.png?m=1723538556" }, "url": "t/833872", "title": "Sinatra \u6e90\u7801\u5206\u6790 (\u4e00):set \u7cfb\u7edf\u5de5\u4f5c\u539f\u7406", "id": "t/833872", "date_published": "2022-02-14T14:59:28+00:00", "content_html": "

\u6211\u7684 BLOG

\n

\u524d\u8a00

\n

\u5927\u5bb6\u597d\uff0c\u6211\u662f MARK24 \u3002\u53ef\u4ee5\u53eb\u6211 MARK \u3002\u8fd9\u662f\u6211\u7814\u7a76 Sinatra \u7684\u7b14\u8bb0\u3002

\n

\u9605\u8bfb\u8fc7\u7a0b\u5927\u7ea6 10 \u5206\u949f\u3002

\n

\u57fa\u4e8e Sinatra 2.1.0 \u8fdb\u884c\u8ba8\u8bba

\n

Sinatra v2.1.0 Fork \u4ee3\u7801\u5730\u5740

\n

Sinatra set \u4ecb\u7ecd

\n

set \u7cfb\u7edf\u53ef\u4ee5\u8ba9 Sinatra \u5728\u81ea\u8eab\u81ea\u7531\u7684\u5b9a\u4e49 \u8bbe\u7f6e\u76f8\u5173\u7684\u53d8\u91cf\u3002

\n

\u6bd4\u5982\u5b9a\u4e49\u6a21\u677f\u6240\u5728\uff1a

\n
set :views, settings.root + '/templates'\n
\n

\u5b9a\u4e49 session secret\uff1a

\n
set :session_secret, ENV.fetch('SESSION_SECRET') { SecureRandom.hex(64) }\n
\n

\u7b49\u7b49\uff0c\u975e\u5e38\u81ea\u7531\u4e14\u7075\u6d3b\u3002

\n

set \u7cfb\u7edf\u8fd9\u90e8\u5206\u7684\u6e90\u7801\u6070\u5de7\u662f\u53ef\u4ee5\u7b80\u5355\u4fee\u6539\u4e4b\u540e\u72ec\u7acb\u5de5\u4f5c\u7684\u3002\u6458\u8981\u5982\u4e0b\uff1a

\n
# https://github.com/Mark24Code/sinatra-code-review/blob/master/lib/sinatra/base.rb#L1267\n\n\ndef define_singleton(name, cOntent= Proc.new)\n singleton_class.class_eval do\n undef_method(name) if method_defined? name\n String === content ? class_eval(\"def #{name}() #{content}; end\") : define_method(name, &content)\n end\nend\n\n\ndef set(option, value = (not_set = true), ignore_setter = false, &block)\n raise ArgumentError if block and !not_set\n value, not_set = block, false if block\n\n if not_set\n raise ArgumentError unless option.respond_to?(:each)\n option.each { |k,v| set(k, v) }\n return self\n end\n\n if respond_to?(\"#{option}=\") and not ignore_setter\n return __send__(\"#{option}=\", value)\n end\n\n setter = proc { |val| set option, val, true }\n getter = proc { value }\n\n case value\n when Proc\n getter = value\n when Symbol, Integer, FalseClass, TrueClass, NilClass\n getter = value.inspect\n when Hash\n setter = proc do |val|\n val = value.merge val if Hash === val\n set option, val, true\n end\n end\n\n define_singleton(\"#{option}=\", setter)\n define_singleton(option, getter)\n # \u539f\u59cb\u4ee3\u7801\u653e\u5728\u4e00\u4e2a\u7c7b\u4e2d\uff0c \u5982\u679c\u6211\u4eec\u60f3\u653e\u5728\u5355\u6587\u4ef6\u6267\u884c\uff0c\u9700\u8981 \u6539\u5199\u4e3a `self.class.method_defined?` \u8c03\u7528\u5230\u65b9\u6cd5\n # define_singleton(\"#{option}?\", \"!!#{option}\") unless method_defined? \"#{option}?\"\n define_singleton(\"#{option}?\", \"!!#{option}\") unless self.class.method_defined? \"#{option}?\"\n self\nend\n
\n

set \u6e90\u7801\u5206\u6790

\n

Sinatra \u5185\u90e8\u5b9e\u73b0\u4e86\u4e00\u5957 \u914d\u7f6e\u7cfb\u7edf\uff0c\u57fa\u4e8e\u4e00\u4e2a DSL \u8bed\u6cd5 set \u3002 \u8fd9\u662f Sinatra Class \u90e8\u5206\u521d\u59cb\u5316\u4e4b\u540e\u552f\u4e00\u7684\u521d\u59cb\u5316\u7684 DSL \u3002Sinatra \u6ca1\u6709\u505a\u5f88\u591a\u590d\u6742\u7684\u524d\u7f6e\u5de5\u4f5c\u3002

\n

\u4e00\u81f4\u5f88\u8ba9\u6211\u7591\u60d1\u7684\u662f\uff0c\u8fd9\u91cc\u7684 getter \u3001setter \u3002\u6211\u4eec\u4f20\u7edf\u7406\u89e3\u7684 \u662f\u8fd9\u6837\u5de5\u4f5c\u7684\uff1a

\n
\nclass Sample\n def initialize()\n @name\n end\n\n # getter\n def name\n @name\n end\n\n # setter\n def name=(new_name)\n @name = new_name\n end\nend\n
\n

\u4f46\u662f Sinatra \u8fd9\u91cc\u4f3c\u4e4e\u662f\u4e00\u4e2a\u5faa\u73af\u4e00\u6837\u7684\uff0c\u4f60\u4f1a\u53d1\u73b0\u4ed6\u7684 setter \u6c38\u8fdc\u5728\u8c03\u7528 set \u8fd9\u662f\u4e3a\u4ec0\u4e48\u5462\uff1f\u6211\u4e00\u5ea6\u975e\u5e38\u8ff7\u60d1\u3002

\n
setter = proc { |val| set option, val, true }\n
\n

\u6211\u521a\u5f00\u59cb\u8fdb\u5165\u8fd9\u6bb5\u662f\u767e\u601d\u4e0d\u5f97\u5176\u89e3\u3002\u4f46\u4e8b\u5b9e\u8bc1\u660e\u6211\u683c\u5c40\u5c0f\u4e86\u3002\u8fd9\u90e8\u5206\u5176\u5b9e\u6839\u672c\u4e0d\u662f\u4f20\u7edf\u7684 setter, \u6211\u4eec\u89c2\u5bdf\u4f20\u7edf\u7684 setter \u4ed6\u7684\u95ee\u9898\u662f\u5fc5\u987b\u8981\u4ee5\u4e00\u4e2a\u5b9e\u4f8b\u53d8\u91cf\u4e3a\u4f9d\u6258\u3002\u6240\u4ee5\u4ed6\u624d\u5fc5\u987b\u5199\u6210\u8fd9\u6837\u3002\n\u5982\u679c\u662f\u4e0b\u9762\u8fd9\u6837\u5462\uff1f

\n
class Sample\n\n # getter\n def name\n \"new value\"\n end\n\n # setter\n def name=(new_name)\n # setter \u7684\u903b\u8f91\uff0c\u5c31\u662f\u8986\u76d6\u5f0f\u5b9a\u4e49\u4e00\u4e2a \u65b0\u7684 \u76f4\u63a5\u8fd4\u56de\u65b0\u503c\u7684 getter\n re_define_name_getter(new_name)\n end\nend\n
\n

\u76f4\u63a5\u4f2a\u4ee3\u7801\uff0c\u6211\u4eec\u6bcf\u6b21\u8c03\u7528 setter \uff0csetter \u7684\u4efb\u52a1\u4e0d\u662f\u53bb\u4fee\u6539\u4e00\u4e2a \u4e2d\u95f4\u503c\uff0c\u800c\u662f\u6bcf\u6b21\u53bb\u91cd\u65b0\u5b9a\u4e49 \u65b0\u7684 getter \u65b9\u6cd5\uff0c\u5b9a\u4e49\u7684\u65f6\u5019\u5c31\u585e\u5165\u65b0\u7684\u503c\u3002

\n

\u8fd9\u6837\u4f9d\u7136\u4fdd\u6301\u4e86 getter \u7684\u529f\u80fd\uff01\u8c41\u7136\u5f00\u6717\uff01

\n

Sinatra \u7684 set \u7cfb\u7edf\u5c31\u662f\u8fd9\u6837\u5de5\u4f5c\u7684\uff0c\u4e0d\u8bba\u662f set \u51fd\u6570\u5b9a\u4e49\u672c\u8eab\uff0c\u8fd8\u662f set \u5185\u90e8\u8c03\u7528\u7684 set \uff0c\u8fd8\u662f\u7528\u6237\u6700\u7ec8\u5728\u5916\u90e8\u4e66\u5199 set xxx, new_value \u6700\u7ec8\u6b8a\u9014\u540c\u5f52\u7684\u8fdb\u5165 set option, value, true \u7136\u540e\u90fd\u4f1a\u8d70\u5230\u6700\u540e\u4e00\u90e8\u5206\uff0c\u91cd\u65b0\u5b9a\u4e49\u4e09\u4e2a\u65b9\u6cd5\u3002

\n
 define_singleton(\"#{option}=\", setter)\n define_singleton(option, getter)\n define_singleton(\"#{option}?\", \"!!#{option}\") unless method_defined? \"#{option}?\"\n
\n

setter \u65b9\u6cd5\u7684\u4f5c\u7528\u5c31\u662f\u8c03\u7528 set \u81ea\u8eab\uff0c\u8fd9\u6837\u53ea\u8981\u88ab\u8c03\u7528\uff0c\u65f6\u95f4\u4e0a\u53ef\u4ee5\u5b8c\u6210\u4e86\u4e00\u79cd\u5faa\u73af\u3002\u95ed\u73af\u8c03\u7528\uff08\u539f\u8c05\u6211\u7528\u4e86\u95ed\u73af\u8fd9\u4e2a\u8bcd :P \uff09\ngetter \u65b9\u6cd5 \u662f\u4ee5\u65b0\u7684\u503c\u76f4\u63a5\u8fd4\u56de\uff0crespond_to \u65b9\u6cd5\u540c\u7406\uff0c\u4ee5\u65b0\u503c\u8ba1\u7b97\u8fd4\u56de\u3002

\n

\u8865\u5145

\n

1.\u5b9a\u4e49\u5904\u6709\u8da3\u7684\u5199\u6cd5 value = (not_set = true)

\n
def set(option, value = (not_set = true), ignore_setter = false, &block)\n # ....\nend\n
\n

\u53ef\u4ee5\u901a\u8fc7\u5b9e\u9a8c\u8bc1\u5b9e\u8fd9\u79cd\u5199\u6cd5\u7684\u7279\u70b9\u662f\uff1a

\n

\u5982\u679c value \u8d4b\u503c \u6bd4\u5982\u662f 99 \uff0c\u90a3\u4e48 value = 99, not_set = nil

\n

\u5982\u679c value \u6ca1\u6709\u8d4b\u503c\uff0c \u90a3\u4e48 value = not_set = true

\n

\u8fd9\u91cc\u4e3b\u8981\u662f\u6ca1\u6709\u8d4b\u503c\uff0cnot_set \u5f00\u59cb\u53d1\u6325\u903b\u8f91\u4e0a\u7684\u4f5c\u7528\u3002

\n

\u6211\u7684 BLOG

\n" }, { "author": { "url": "member/Mark24", "name": "Mark24", "avatar": "https://cdn.v2ex.com/avatar/edea/c9b0/62847_large.png?m=1723538556" }, "url": "t/822114", "title": "\u300aRuby \u8bbe\u8ba1\u6a21\u5f0f\u300b\u7b14\u8bb0", "id": "t/822114", "date_published": "2021-12-14T05:54:52+00:00", "content_html": "

\u7b97\u662f\u79c1\u4eba\u7b14\u8bb0\u3002\u4f46\u662f\u8bb0\u5f55\u4e0b\u4e5f\u8bb8\u9700\u8981\u4eba\u53ef\u4ee5\u83b7\u5f97\u6709\u4ef7\u503c\u7684\u4fe1\u606f\u3002

\n

\u8fd9\u672c\u4e66\u7edd\u7248\u4e86

\n

Ruby \u8bbe\u8ba1\u6a21\u5f0f\u7b14\u8bb0

\n" }, { "author": { "url": "member/Mark24", "name": "Mark24", "avatar": "https://cdn.v2ex.com/avatar/edea/c9b0/62847_large.png?m=1723538556" }, "url": "t/820700", "title": "Ruby \u6807\u51c6\u5e93\u6709\u8da3\u90e8\u5206\u6458\u8981", "id": "t/820700", "date_published": "2021-12-07T11:07:04+00:00", "content_html": "

\u6211\u7684 BLOG https://mark24code.github.io/ruby/2021/12/07/Ruby%E6%A0%87%E5%87%86%E5%BA%93%E6%9C%89%E8%B6%A3%E9%83%A8%E5%88%86%E6%91%98%E8%A6%81.html

\n

\u6458\u8981

\n\n

\u672a\u5b8c\u5f85\u7eed

\n" }, { "author": { "url": "member/Mark24", "name": "Mark24", "avatar": "https://cdn.v2ex.com/avatar/edea/c9b0/62847_large.png?m=1723538556" }, "url": "t/807831", "title": "\u5e76\u884c\u5e76\u53d1\u8fdb\u7a0b\u7ebf\u7a0b\u534f\u7a0b GIL \u6982\u5ff5\u7b80\u660e\u89e3\u91ca\u7b14\u8bb0\uff08Ruby \u4e3e\u4f8b\uff09", "id": "t/807831", "date_published": "2021-10-14T08:05:35+00:00", "content_html": "

\u5e76\u884c\u5e76\u53d1\u8fdb\u7a0b\u7ebf\u7a0b\u534f\u7a0b GIL \u6982\u5ff5\u7b80\u660e\u89e3\u91ca\u7b14\u8bb0

\n

\u6700\u5148\u53d1\u5728 Ruby \u8282\u70b9\uff0c\u56e0\u4e3a\u4f8b\u5b50\u91cc\u4e3b\u8981\u4e3e\u4e86 Ruby

\n

\u7531\u4e8e GIL \u7684\u95ee\u9898\uff0c\u5bf9\u4e8e Python \u4e5f\u6709\u540c\u6837\u7684\u610f\u4e49\uff0c\u6240\u4ee5\u53d1\u5728\u4e86 Python \u8282\u70b9\uff0c\u770b\u7684\u4eba\u591a\u4e00\u70b9

\n" }, { "author": { "url": "member/Mark24", "name": "Mark24", "avatar": "https://cdn.v2ex.com/avatar/edea/c9b0/62847_large.png?m=1723538556" }, "url": "t/801866", "title": "Sinatra \u7684 app \u6a21\u677f\uff0c\u63d0\u4f9b\u4e00\u4e9b\u80f6\u6c34\u4ee3\u7801\u652f\u6301\u7c7b\u4f3c Rails \u7684\u4f53\u9a8c", "id": "t/801866", "date_published": "2021-09-14T15:02:45+00:00", "content_html": "

Sinatra \u7684 app \u6a21\u677f\uff0c\u63d0\u4f9b\u4e00\u4e9b\u80f6\u6c34\u4ee3\u7801\u652f\u6301\u7c7b\u4f3c Rails \u7684\u4f53\u9a8c

\n

\u5982\u679c\u4f60\u60f3\u7075\u6d3b\u7684\u5f00\u5c55\u5de5\u4f5c\uff0c\u53c8\u89c9\u5f97 Rails \u8fc7\u4e8e\u5e9e\u5927\uff08\u6bd4\u5982 Rails6+ \u643a\u5e26\u4e00\u4e2a Node \uff09\u3001\u6587\u6863\u8981\u8bfb\u5f88\u4e45\uff0c\u6b63\u5728\u72b9\u8c6b\u5f53\u4e2d\u3002

\n

\u4f60\u6070\u5de7\u77e5\u9053 Sinatra \u7684\u5b58\u5728\uff0c15 \u5206\u949f\u8bfb\u5b8c\u7684 Sinatra/README \u53c8\u89c9\u5f97\u81ea\u5df1\u884c\u4e86\uff0c\u53ef\u662f Sinatra \u4f3c\u4e4e\u592a\u7b80\u5355\u4e86\uff0c\u4f60\u60f3\u8981\u662f Sinatra \u6709 MVC \u548c\u5f00\u7bb1\u5373\u7528\u7684 ORM \u5c31\u597d\u4e86\u3002

\n

\u8fd9\u662f\u6700\u8fd1\u505a\u4e00\u4e2a\u7b80\u5355\u540e\u7aef\u9879\u76ee\u7684\u6c89\u6dc0\uff0c\u53ef\u4ee5\u4f5c\u4e3a\u4e00\u4e2a\u7b80\u5355\u7684\u8d77\u70b9\u3002

\n

\u4e00\u5207\u57fa\u4e8e Sinatra+Rack\uff0c\u7528\u4e00\u4e9b\u80f6\u6c34\u4ee3\u7801 \u628a Rack/Sinatra + \u914d\u7f6e + \u6587\u4ef6\u76ee\u5f55 \u8054\u7cfb\u5728\u4e00\u8d77\u5f00\u59cb\u5de5\u4f5c\u3002\u5bb9\u6613\u66f4\u6539\uff0c\u7b80\u5355\u660e\u4e86\u3002

\n

\u5206\u4eab\u4e00\u4e0b\uff0c\u53ef\u80fd\u4e0d\u591f\u6210\u719f\uff0c\u6b22\u8fce\u78b0\u649e\uff0c\u8ba9\u6211\u53ef\u4ee5\u5b66\u4e60\u66f4\u591a~

\n

github\uff1a https://github.com/Mark24Code/sinatra-app-template

\n

geeknote\uff1a https://geeknote.net/mark24/posts/283

\n

RubyChina: https://ruby-china.org/topics/41685

\n

Sinatra App Template

\n

Lightweight web framework codebase. Just clone and develop on it.

\n

Tech component: Rack+Sinatra+Sequel and default use Postgresql database.

\n

Add rails-like migration command line helpers.

\n

Openbox Features

\n

Apps

\n\n

Tasks

\n\n

CI&CD

\n\n

Find helpful rake tasks

\n

rake or rake -T

\n

Run server & develop

\n

rake server:run

\n

Production Server & deploy

\n

APP_ENV=production bundle exec rake server:run

\n

you can also use docker

\n

docker built -t <what your docker image label> .

\n

Custom server & database

\n

You can use DSL to config Key:Value , then you application just use.

\n
Config::Default.configure do\n set :app_env, ENV.fetch('APP_ENV'){ 'development' }\n set :bind, ENV.fetch('HOST') { '0.0.0.0' }\n set :port, ENV.fetch('PORT') { 3000 }\n set :secrets, ENV.fetch('SECRETS') { 'YOU CANNOT GUESS ME' }\n set :max_threads, ENV.fetch('MAX_THREADS') { 5 }\n\n set :database_url, ENV['DATABASE_URL']\nend\n\nConfig::Development.configure do \n set :database_url, 'ENV['DATABASE_URL']'\nend\n\nConfig::Test.configure do \n set :database_url, ENV['DATABASE_URL']\nend\n\nConfig::Production.configure do \n # set :database_url, ENV['DATABASE_URL']\nend\n
\n

They have an inheritance relationship

\n
Development < Default\nTest < Default\nProduction < Default\n
\n

In your code, just use Config directly. core/bootstrap do a work that loaded all necessery mods before your code.

\n
Config.current # current env configuration\n\nConfig::Development.database_url\n\nConfig::Development\n\nConfig::Development.database_url\n
\n

You can also create your own Config for your single Application:

\n
class MyConfig < Config::Base\n\nend\n\nMyConfig.configure do \n # set :database_url, ENV['DATABASE_URL']\nend\n\n
\n

Mount different Sinatra web application

\n

Edit config.ru

\n

Lark also is Rack application. We can use Rack middlewares.

\n
require_relative './cores/bootstrap'\nBootstrap.rack \n\n# you can load Rack middleware here\n\n# mount applications\nrequire 'controllers/root_controller'\n# routers(handy config)\nmap '/' do\n run RootController \nend\n
\n

Base

\n

bases directory are use for Application Base Class.

\n

You can make different Configured Sinatra Application class here, then your application/controller just inherit the Base Class to create Application.

\n

It will share Config, and make less code.

\n
# Sinatra Doc http://sinatrarb.com/intro.html\nrequire 'sinatra/base'\nrequire 'json'\n\nclass BaseController < Sinatra::Base\n # Inject config\n\n # Config & register Sinatra Extensions\n\n # Rewrite Views dir\n settings.views = File.expand_path(File.join($PROJECT_DIR, 'views'))\n\n configure :development do\n require 'sinatra/reloader'\n register Sinatra::Reloader\n end\n\n # mount Sinatra Helpers\n\n # mount Sinatra middlewares\n\nend\n\n\n# Share Configuration\n\nclass MyPageServer < BaseController\nend\n\nclass MyApiServer < BaseController\nend\n\n
\n

ORM & Tools

\n

Provide rails-like rake task help you build app quickly.

\n
rake db:check # Checking for current migrations\nrake db:connect # Connect database\nrake db:console # Database Console\nrake db:create[database_name] # Create database\nrake db:create_migration[name] # Create a migration\nrake db:drop[database_name] # Drop database\nrake db:ls # List database tables\nrake db:migrate[version] # Run migrations\nrake db:rollback[version] # Rollback to migration\nrake db:version # Prints current schema version\nrake list # List all tasks\nrake seed:all # Seed: run all seeds\nrake seed:run[seed_name] # Seed: run seed\nrake server:run # Run server\nrake test # Run tests\n
\n

Project Structure

\n
.\n\u251c\u2500\u2500 Dockerfile # Common Dockerfile\n\u251c\u2500\u2500 Gemfile\n\u251c\u2500\u2500 Gemfile.lock\n\u251c\u2500\u2500 README.md\n\u251c\u2500\u2500 Rakefile # Rake Task Index File.\n\u251c\u2500\u2500 bases # Base configured class. You can make different BaseClasses then reuse them.\n\u2502 \u2514\u2500\u2500 base_controller.rb # You contoller can inherit it or write yourself.\n\u251c\u2500\u2500 config.ru # Application index. You can mount controllers and routes here.\n\u251c\u2500\u2500 configs # You can make different configs for applications\n\u2502 \u2514\u2500\u2500 config.rb # Base config\n\u251c\u2500\u2500 controllers \n\u2502 \u2514\u2500\u2500 root_controller.rb\n\u251c\u2500\u2500 cores # Inject ENVS and autoloads files, make MVC works\n\u2502 \u251c\u2500\u2500 01_config.rb # Names can controller mount order\n\u2502 \u2514\u2500\u2500 bootstrap.rb\n\u251c\u2500\u2500 dbs # You can make multi database here\n\u2502 \u251c\u2500\u2500 default_db.rb # default database connect instance\n\u2502 \u2514\u2500\u2500 migrations # save database migrations\n\u251c\u2500\u2500 docs\n\u2502 \u2514\u2500\u2500 good.feature\n\u251c\u2500\u2500 log # Directory for save logs by default\n\u2502 \u2514\u2500\u2500 development.log\n\u251c\u2500\u2500 loggers # Loggers for application\n\u2502 \u2514\u2500\u2500 default_logger.rb\n\u251c\u2500\u2500 public # Public resources\n\u2502 \u2514\u2500\u2500 favicon.svg\n\u251c\u2500\u2500 seeds # Seeds\n\u251c\u2500\u2500 tasks # Rake helpful tasks \n\u2502 \u251c\u2500\u2500 db_task.rb\n\u2502 \u251c\u2500\u2500 seed_task.rb\n\u2502 \u251c\u2500\u2500 server_task.rb\n\u2502 \u2514\u2500\u2500 test_task.rb\n\u251c\u2500\u2500 tests # Test cases\n\u2502 \u2514\u2500\u2500 test_demo.rb\n\u2514\u2500\u2500 views # views template\n \u251c\u2500\u2500 base.erb\n \u2514\u2500\u2500 root.erb\n\n
\n

Bootstrap & Load orders

\n

For Rake

\n
require_relative './cores/bootstrap'\nBootstrap.rake\n
\n

It will auto load files make sure rake task can work.

\n

In rake we can use Config.current to read configuration.

\n

DB also available.

\n

For Rack/Applications

\n

In the same way

\n
require_relative './cores/bootstrap'\nBootstrap.rack\n# OR\n# Bootstrap.apps\n
\n

It will autoload all dep mods. Share with a context.

\n

Change load orders

\n

cores/bootstrap.rb defines different load orders, you can change.

\n

In anther way, you can change filename to e.g 00_before_all.rb \u300101_first_load.rb to control mods load order.

\n" }, { "author": { "url": "member/Mark24", "name": "Mark24", "avatar": "https://cdn.v2ex.com/avatar/edea/c9b0/62847_large.png?m=1723538556" }, "url": "t/792532", "date_modified": "2021-07-29T10:53:00+00:00", "content_html": "

\u6709\u66f4\u597d\u7684\u65b9\u6cd5\u53ef\u4ee5\u544a\u8bc9\u6211\uff0c\u6211\u6700\u65b0\u5728\u5b66\u4e60 Ruby

\n

\u6700\u65b0\u7684\u4fee\u6539\u4f1a\u66f4\u65b0\u5728 BLOG

\n

\u6211\u7684\u535a\u5ba2

\n

RubyChina \u8ba8\u8bba\u5e16

\n
\n

\u80cc\u666f

\n

\u300a Ruby \u5143\u7f16\u7a0b\uff08\u7b2c\u4e8c\u7248\uff09\u300b 5.4 \u8282 \u5355\u4ef6\u7c7b \u5728 Page125 \u8fd9\u9875\uff0c\u8bb2\u4e86\u4e00\u79cd\u60c5\u51b5\uff1a

\n
\nclass C\n def a_method\n 'C#a_method()'\n end\nend\n\n\n\nclass C\n class << self\n def a_class_method\n '#C.a_class_method() #singleton'\n end\n end\nend\n\nclass D < C;end\n\nobj = D.new\n\n\nD.a_class_method # => '#C.a_class_method() #singleton'\n
\n

D.a_class_method \u4ed6\u662f\u5982\u4f55\u67e5\u627e\u7684\u5462\uff1f

\n

\u672c\u6587\u5c31\u662f\u5bfb\u627e\u8fd9\u4e2a\u7684\u7b54\u6848\u3002\u8bb2\u7684\u662f Ruby \u7684\u65b9\u6cd5\u67e5\u627e\u518d\u5f80\u524d\u8d70\u4e00\u6b65\u3002

\n

\u4e3a\u4e86\u8bf4\u660e\u8fd9\u4e2a\u95ee\u9898\uff0c\u5148\u8981\u5570\u55e6\u7684\u505a\u4e00\u4e9b\u94fa\u57ab\u3002

\n

\u4e0b\u6587\u4e2d\uff0c\u6b64\u4e66\u7b80\u79f0\u4e3a\u300a\u5143\u7f16\u7a0b\u300b

\n

\u4e00\u3001Ruby \u7684\u7ee7\u627f\u7ed3\u6784

\n

\"\"

\n

\u8fd9\u5f20\u56fe\u5b9e\u5728\u603b\u7ed3\u7684\u592a\u7f8e\u4e3d\u4e86\u3002\u5148\u653e\u5728\u8fd9\u91cc\u3002\u56fe\u7247\u7684\u51fa\u5904\uff0c\u53ef\u4ee5\u53c2\u8003\u6587\u672b\u3002

\n

\u4e8c\u3001Ruby \u4e00\u822c\u65b9\u6cd5\u67e5\u627e\u89c4\u5219

\n

\u300a\u5143\u7f16\u7a0b\u300b\u91cc\u9762\u91cc\u9762\u603b\u7ed3\u4e86 Ruby \u7684\u67e5\u627e\u89c4\u5219\uff1a

\n
\n

\u201c\u5411\u53f3\u4e00\u6b65\uff0c\u7136\u540e\u5411\u4e0a\u67e5\u627e\u201d\u3002

\n
\n

\u610f\u601d\u5c31\u662f\uff0c\u5411\u53f3\u5bfb\u627e\u4ed6\u7684\u7236\uff0c\u7136\u540e\u5f00\u59cb\u5f80\u4e0a\u5bfb\u627e\u7ee7\u627f\u5173\u7cfb\uff0c\u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\u67e5\u627e\u65b9\u6cd5\u3002

\n

\u6bd4\u5982\u4ee5\u4e0b\u4ee3\u7801

\n
class C\n def a_method\n 'C#a_method()'\n end\nend\n\n\nclass D < C;end\n\nobj = D.new\nobj.a_method\n
\n

obj \u5982\u4f55\u67e5\u627e a_method \u65b9\u6cd5\u5462\uff1f

\n

\"\"

\n

\u5982\u679c\u6211\u4eec\u7ed9 obj \u5bf9\u8c61\u6dfb\u52a0\u5355\u4f8b\u7c7b\uff0c\u4ed6\u4f1a\u5982\u4f55\u67e5\u627e\u5462\uff1f

\n
\nclass C\n def a_method\n 'C#a_method()'\n end\nend\n\n\nclass D < C;end\n\nobj = D.new\n\n# \u5b9a\u4e49\u5355\u4f8b\u7c7b\n\nclass << obj\n def a_singleton_method\n \"obj#a_singleton_method\"\n end\nend\n\nobj.a_singleton_method \n\n
\n

obj.a_singleton_method \u4f1a\u5982\u4f55\u67e5\u627e\u65b9\u6cd5\u5462\uff1f

\n

\"\"

\n

\u53ef\u4ee5\u901a\u8fc7\u4e00\u4e0b\u65b9\u5f0f\u68c0\u9a8c

\n
\nobj.singleton_class.superclass # => D\n\n
\n

\u4ed6\u4f1a\u6309\u7167\u5982\u56fe\u7684\u65b9\u5f0f\uff0c\u5176\u5b9e\u5b9e\u4f8b\u5bf9\u8c61\u521b\u9020\u4e86\u4e00\u4e2a \u5355\u4f8b\u7c7b \u53ef\u4ee5\u6807\u8bb0\u4e3a #obj\uff0c\u7528#\u8868\u793a\u5355\u4f8b\u7c7b\u3002\n#obj \u4f1a\u51fa\u73b0\u5728\u5bf9\u8c61\u548c\u771f\u6b63\u7684\u7c7b\u4e2d\u95f4\u3002

\n

\u6211\u4eec\u4e5f\u80fd\u7528\u4e0a\u9762

\n
\n

\u201c\u5411\u53f3\u4e00\u6b65\uff0c\u7136\u540e\u5411\u4e0a\u67e5\u627e\u201d\u3002

\n
\n

\u6765\u6307\u5bfc\u6211\u4eec\u67e5\u627e\uff0c\u53ea\u4e0d\u8fc7\u5bf9\u8c61\u5b58\u5728\u4e00\u4e2a\u5355\u4f8b\u7c7b\u7f62\u4e86\u3002

\n

\u4e09\u3001\u65b0\u7684\u95ee\u9898\u51fa\u73b0

\n

\u4f46\u662f\u95ee\u9898\u6765\u4e86\uff0c\u56de\u5230\u6587\u7ae0\u7684\u6700\u5f00\u5934\u3002

\n
\nclass C\n def a_method\n 'C#a_method()'\n end\nend\n\n\n\nclass C\n class << self\n def a_class_method\n '#C.a_class_method() #singleton'\n end\n end\nend\n\nclass D < C;end\n\nobj = D.new\n\n\nD.a_class_method # => '#C.a_class_method() #singleton'\n
\n

\u8fd9\u4e2a\u4f8b\u5b50\u3002\u5728\u7c7b C \u4e0a\u5b9a\u4e49\u4e86\u5355\u4f8b\u65b9\u6cd5\uff0c\u5e76\u4e14\u6211\u4eec\u6307\u5bfc\u6240\u6709\u4e1c\u897f\u5728 Ruby \u91cc\u90fd\u662f\u5bf9\u8c61\uff0c\u90fd\u53ef\u4ee5\u5b9a\u4e49\u5355\u4f8b\u65b9\u6cd5\u3002

\n

\u8fd9\u5c31\u662f\u6587\u7ae0\u5f00\u5934\u6700\u5148\u7684\u56fe\u7247\u3002\u6240\u6709\u7684\u7c7b\u90fd\u53ef\u4ee5\u5b9a\u4e49\u5355\u4f8b\u7c7b\u3002\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0cD.a_class_method \u5e94\u8be5\u5982\u4f55\u67e5\u627e\u5462\uff1f

\n
\n

\u201c\u5411\u53f3\u4e00\u6b65\uff0c\u7136\u540e\u5411\u4e0a\u67e5\u627e\u201d\u3002

\n
\n

\u4f3c\u4e4e\u5e2e\u4e0d\u4e86\u6211\u4eec\u4e86\u3002\u56e0\u4e3a\u6211\u4eec\u9762\u4e34\u4e00\u4e2a\u95ee\u9898\uff0c\u8ba9\u6211\u6765\u63cf\u8ff0\u4e0b\uff1a

\n

\u6211\u4eec\u628a D \u5f53\u505a\u4e00\u4e2a\u5bf9\u8c61\uff0c\u5f00\u59cb\u5bfb\u627e\u4ed6\u7684\u65b9\u6cd5\u3002

\n

\"\"

\n

\u62ff\u8fd9\u5e45\u56fe\u505a\u4f8b\u5b50:

\n

Dog \u5f00\u59cb\u5bfb\u627e\u5b9a\u4e49\u7684\u65b9\u6cd5\uff0c\u5411\u53f3\u4e00\u6b65\uff0c\u8fdb\u5165\u81ea\u5df1\u7684 \u5355\u4f8b\u7c7b #Dog\uff0c\u7136\u540e\u5e94\u8be5\u505a\u4ec0\u4e48\uff0c\u9009\u62e9\u5411\u4e0a\u4e48\uff1f\u662f\u8d70 \u4ed6\u7684\u7236\u7c7b Class\uff0c\u8fd8\u662f \u5e94\u8be5\u5f80 \u5355\u4f8b\u7c7b\u7684\u7ee7\u627f\u94fe\u5f80\u4e0a\u627e\u5462\uff1f

\n

\u300a\u5143\u7f16\u7a0b\u300b\u6587\u672b\u7684\u51e0\u53e5\u8bdd,\u4f3c\u4e4e\u5728\u6697\u793a\u9ec4\u8272\u8fd9\u6761\u7ebf\u7684\u5bfb\u627e\u65b9\u5411\uff0c\u4f46\u662f\u4f5c\u8005\u5e76\u6ca1\u6709\u771f\u6b63\u8bf4\u6e05\u695a\uff1a

\n

\"\"

\n

\u4e09\u3001\u5bfb\u627e\u7b54\u6848

\n

\u6211\u5148\u653e\u51fa\u7b54\u6848\uff0c\u5982\u4e0b\u56fe\u6240\u793a\uff1a

\n

\"\"

\n

\u5bf9\u8c61\u7684\u65b9\u6cd5\uff0c\u9075\u5faa

\n
\n

\u201c\u5411\u53f3\u4e00\u6b65\uff0c\u7136\u540e\u5411\u4e0a\u67e5\u627e\u201d\u3002

\n
\n

\u7c7b\u65b9\u6cd5\u7684\u67e5\u627e\u662f\u6211\u4eec\u5173\u5fc3\u7684\uff0c\u53ef\u4ee5\u770b\u5230\u5b9e\u9645\u7ed3\u679c\u662f\uff0c\u5b83\u6cbf\u7740\u7ee7\u627f\u7684\u5355\u4f8b\u7c7b\u4e00\u8def\u5411\u4e0a\uff0c\u7136\u540e\u518d\u8fdb\u5165\u7236\u7c7b\u3002

\n

\u5bfb\u627e\u8fd9\u4e2a\u7b54\u6848\u7684\u8fc7\u7a0b\u4e2d\uff0c\u6211\u770b\u4e86\u633a\u591a\u8d44\u6599\u548c\u6587\u5b57,\u8fd8\u6709\u95ee\u4e00\u4e9b Ruby \u65b9\u9762\u7684\u670b\u53cb\u90fd\u6ca1\u6709\u771f\u6b63\u5206\u6790\u5230\u8fd9\u4e00\u6b65\u3002

\n

\u6211\u6700\u540e\u662f\u600e\u4e48\u627e\u5230\u7b54\u6848\u7684\u5462\uff1f \u8fd9\u5c31\u5f97\u501f\u52a9 Ruby \u81ea\u8eab\u5b8c\u5584\u7684\u81ea\u7701\u673a\u5236\u3002\uff08\u5410\u69fd\uff0c\u5176\u4ed6\u8bed\u8a00\u53ef\u80fd\u90fd\u6ca1\u6709\u5b9e\u73b0\u7684\u90a3\u4e48\u7ec6\u81f4\uff09\u3002

\n

\u5176\u5b9e Ruby \u81ea\u8eab\u7684\u5f88\u591a\u5c5e\u6027\u90fd\u7ed1\u5b9a\u5728\u81ea\u8eab\u4e86\uff0c\u76f4\u63a5\u5411 Ruby \u95ee\u7b54\u6848\u5c31\u597d\u4e86

\n
\nclass C\n def a_method\n 'C#a_method()'\n end\nend\n\n\n\nclass C\n class << self\n def a_class_method\n '#C.a_class_method() #singleton'\n end\n end\nend\n\nclass D < C;end\n\nobj = D.new\n\n\nD.a_class_method # => '#C.a_class_method() #singleton'\n
\n

\u6211\u4eec\u77e5\u9053 obj.ancestors \u53ef\u4ee5\u6253\u5370\u7ee7\u627f\u5173\u7cfb\uff0c\u4f46\u662f\u8fd9\u4e2a\u5f88\u9057\u61be\u7684\u662f\u5b83\u4e0d\u4f1a\u6253\u5370 \u5355\u4f8b\u7c7b\u3002

\n

\u5355\u4f8b\u7c7b\u5b9e\u9645\u4e0a\u662f\u4e00\u4e2a\u9690\u85cf\u7684\u5b58\u5728\u3002\u8fd9\u4e5f\u5c31\u662f\u7814\u7a76\u8fd9\u4e2a\u95ee\u9898\u5f88\u96be\u5f97\u5730\u65b9\uff0c\u56e0\u4e3a\u9690\u85cf\uff0c\u4f3c\u4e4e\u53ea\u80fd\u901a\u8fc7\u6e90\u7801\u548c\u5916\u90e8\u8d44\u6599\u53bb\u67e5\u770b\u3002

\n

\u5b9e\u9645\u4e0a\u6211\u4eec\u662f\u53ef\u4ee5\u62ff\u5230 obj.singleton_class \u7684\uff0c\u7136\u540e\u6211\u4eec\u524d\u9762\u5206\u6790\u4e86\u4e00\u4e9b\u7ed3\u8bba\uff0c\u5927\u81f4\u7ed9\u51fa\u4e86\u4e00\u4e2a\u5bf9\u8c61\u7684\u7ee7\u627f\u6a21\u578b\u3002

\n
obj.singleton_class.ancestors\n\n# => [#<Class:#<D:0x00007feae092efc8>>, D, C, Object, Kernel, BasicObject]\n
\n

\u5c31\u53ef\u4ee5\u6253\u5370\u51fa\uff0c\u5bf9\u8c61\u67e5\u627e\u7684\u987a\u5e8f\u3002

\n

\u540c\u7406\uff0c\u6211\u4eec\u60f3\u8981\u77e5\u9053 D \u7684\u65b9\u6cd5\u7684\u67e5\u627e\u987a\u5e8f

\n
D.singleton_class.ancestors\n\n# => [#<Class:D>, #<Class:C>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]\n
\n

\u8fd9\u4e2a\u5176\u5b9e\u5c31\u662f D \u67e5\u627e\u65b9\u6cd5\u7684\u987a\u5e8f\uff0c\u53ef\u4ee5\u770b\u5230\uff0c\u4ed6\u5148\u662f\u628a\u6240\u6709\u7684\u5355\u4f8b\u7c7b\u8d70\u4e86\u4e00\u904d\uff0c\u7136\u540e\u5f00\u59cb\u8fdb\u5165\u81ea\u5df1\u7684\u7236\u3002

\n

\u56db\u3001\u603b\u7ed3

\n

\u6700\u540e\uff0c\u8fd9\u53e5\u8bdd

\n
\n

\u201c\u5411\u53f3\u4e00\u6b65\uff0c\u7136\u540e\u5411\u4e0a\u67e5\u627e\u201d\u3002

\n
\n

\u6709\u4e86\u65b0\u5185\u6db5\uff0c \u5411\u53f3\u4e00\u6b65\u7684\u8fc7\u7a0b\u4e2d\uff0c\u4f18\u5148\u7684\u8d70\u5355\u4f8b\u7c7b\uff08\u5982\u679c\u6709\u7684\u8bdd\uff09\u4ee5\u53ca\u5355\u4f8b\u7684\u7ee7\u627f\uff0c\u7ed3\u675f\u540e\uff0c\u5f00\u59cb\u8fdb\u5165\u81ea\u5df1\u771f\u6b63\u7684\u7236\uff0c\u5373\u5411\u4e0a\u5728\u7ee7\u627f\u5173\u7cfb\u4e2d\u5bfb\u627e\u3002

\n

\u5355\u4f8b\u7c7b\u4e5f\u53ef\u4ee5\u770b\u6210\u662f\u4e00\u79cd\u5916\u6302\u65b9\u6cd5\uff08\u6bd4\u55bb\u4e0d\u4e25\u8c28\u4f46\u662f\u5f88\u597d\u7406\u89e3\uff09\uff0c\u5148\u5728\u5916\u6302\u65b9\u6cd5\u91cc\u627e\uff0c\u4e5f\u53ef\u4ee5\u987a\u7740\u5916\u6302\u7ee7\u627f\u94fe\u627e\u3002\u627e\u4e0d\u5230\u518d\u5230\u7ee7\u627f\u5173\u7cfb\u91cc\u9762\u627e\u3002

\n

\u9898\u5916\u8bdd

\n

\u6709\u4eba\u53ef\u80fd\u4f1a\u95ee\uff0c\u4e3a\u5565\u7ee7\u627f\u4f53\u7cfb\u8981\u641e\u5f97\u90a3\u4e48\u590d\u6742\uff1f

\n

\u501f\u7528 \u300a\u5143\u7f16\u7a0b\u300b\u91cc\u9762\u7684\u4e00\u53e5

\n
\n

\u8fd9\u6837\u4f60\u5c31\u53ef\u4ee5\u5728 D \u4e2d \u8c03\u7528 C \u7684\u65b9\u6cd5\u4e86\u3002

\n
\n

\u628a\u5bf9\u8c61\u7a7f\u6210\u94fe\u8868\uff0c\u7136\u540e\u76f8\u5f53\u4e8e\u4f60\u53ef\u4ee5\u62e5\u6709\u548c\u590d\u7528\u8fd9\u4e2a\u94fe\u6761\u4e0a\u6240\u6709\u7684\u65b9\u6cd5\u3002

\n

\u5143\u7f16\u7a0b\u7684\u4e00\u90e8\u5206\u601d\u60f3\u4e5f\u5c31\u662f\u52a8\u6001\u7684\u4fee\u6539\u3001\u521b\u9020\u3001\u8f6c\u53d1\u65b9\u6cd5\u3002\u8fd8\u6709 \u300a\u5143\u7f16\u7a0b\u300b\u91cc\u9762\u63d0\u5230\u7684 \u201c\u81ea\u7531\u65b9\u6cd5\u201d\u6211\u7684\u7406\u89e3\u5c31\u50cf\u662f\u628a\u7ee7\u627f\u94fe\u4e2d\u67d0\u4e9b\u65b9\u6cd5\u590d\u5236\uff0c\u7136\u540e\u7c98\u8d34\u5230\u5f53\u524d\u5bf9\u8c61\u6267\u884c\uff0c\u5728\u7ee7\u627f\u94fe\u4e0a\u8df3\u8dc3\u6267\u884c\u65b9\u6cd5\u2026\u2026

\n

\u8fd9\u4e00\u5207\u90fd\u662f\u4e3a\u4e86\u6781\u5927\u5730\u81ea\u7531\u3002

\n

\u6211\u4ee5\u524d\u4e00\u81f4\u4e0d\u592a\u7406\u89e3\u201cRuby \u662f\u5feb\u4e50\u4f18\u5148\u201d\u8fd9\u53e5\u8bdd\u662f\u4ec0\u4e48\u610f\u601d\uff0c\u73b0\u5728\u6211\u7684\u7406\u89e3\u2014\u2014\u8fd9\u79cd\u5feb\u4e50\u5c31\u662f\u81ea\u7531\uff0c\u62e5\u6709\u81ea\u7531\u7684\u5feb\u4e50\u3002

\n

\u5176\u4ed6

\n

\u56fe\u7247\u6765\u81ea\u6587\u7ae0

\n\n

\u5b89\u5229\u4e00\u6ce2\u4f5c\u8005\u56fe\u7247\u914d\u8272

\n\n

\u53c2\u8003

\n

\u4e66\u7c4d\u63a8\u8350 \u300a Ruby \u5143\u7f16\u7a0b\uff08\u7b2c 2 \u7248)\u300b

\n

BLOG

\n

\u6709\u66f4\u597d\u7684\u65b9\u6cd5\u53ef\u4ee5\u544a\u8bc9\u6211\uff0c\u6211\u6700\u65b0\u5728\u5b66\u4e60 Ruby

\n

\u6700\u65b0\u7684\u4fee\u6539\u4f1a\u66f4\u65b0\u5728 BLOG

\n

\u6211\u7684\u535a\u5ba2

\n

RubyChina \u8ba8\u8bba\u5e16

\n", "date_published": "2021-07-29T10:51:58+00:00", "title": "Ruby \u7684\u65b9\u6cd5\u67e5\u627e\u518d\u5f80\u524d\u4e00\u6b65", "id": "t/792532" }, { "author": { "url": "member/XisucksYi", "name": "XisucksYi", "avatar": "https://cdn.v2ex.com/avatar/96e0/fcf5/467854_large.png?m=1624599525" }, "url": "t/780713", "title": "\u6709\u5728\u6df1\u5733\u81f3\u7b80\u5929\u6210\u7684\u5417\uff1f \u6c42\u52a0\u5fae\u4fe1", "id": "t/780713", "date_published": "2021-06-01T14:00:32+00:00", "content_html": "

\u6211\u5fae\u4fe1\u662f Lebum1995

\n" }, { "author": { "url": "member/putaozhenhaochi", "name": "putaozhenhaochi", "avatar": "https://cdn.v2ex.com/avatar/aa58/d4b1/365763_large.png?m=1755822585" }, "url": "t/738885", "title": "Ruby 3.0.0 Released", "id": "t/738885", "date_published": "2020-12-25T06:10:52+00:00", "content_html": "Ruby 3.0.0 Released

[Ruby 3.0.0 Released]: https://www.ruby-lang.org/en/news/2020/12/25/ruby-3-0-0-released/" }, { "author": { "url": "member/Nonebodysam9", "name": "Nonebodysam9", "avatar": "https://cdn.v2ex.com/avatar/f4d5/e752/298047_large.png?m=1708314645" }, "url": "t/697379", "title": "\u65b0\u5efa\u4e86\u4e2a ruby \u4e2d\u6587\u8ba8\u8bba\u7fa4", "id": "t/697379", "date_published": "2020-08-11T07:04:08+00:00", "content_html": "discord \u7684\uff0c\u7528\u8d77\u6765\u611f\u89c9\u4e0d\u9519

\u9080\u8bf7\u94fe\u63a5 https://discord.gg/jQ9yQ9g" }, { "author": { "url": "member/celadevra", "name": "celadevra", "avatar": "https://cdn.v2ex.com/avatar/467e/7933/21569_large.png?m=1587781884" }, "url": "t/691065", "title": "Language Hopping\uff0c Ruby \u4e3a\u4ec0\u4e48\u4e0d\u706b\uff0c\u4e00\u70b9\u778e\u60f3", "id": "t/691065", "date_published": "2020-07-18T02:12:01+00:00", "content_html": "

\u5728\u6280\u672f\u6808\u95f4\u8df3\u6765\u8df3\u53bb\uff0c\u8bf4\u8d77\u6765\u4e5f\u662f\u8fc1\u5c31\u81ea\u5df1\u7684 ego \u800c\u4e0d\u8003\u8651\u89e3\u51b3\u5b9e\u9645\u95ee\u9898\u7684\u5fc3\u6001\u4f5c\u795f\u3002\u8001\u662f\u9009\u62e9\u65b0\u7684\u8bed\u8a00\u3001\u6846\u67b6\u5c31\u66f4\u662f\u5982\u6b64\u3002

\n

\u8fd9\u80cc\u540e\u7684\u52a8\u529b\u4e00\u90e8\u5206\u662f\u88ab\u666f\u4ef0\u548c\u5c0a\u91cd\u7684\u5fc3\u7406\u9700\u8981\uff08\u522b\u4eba\u90fd\u4e0d\u4f1a\u7528\u7684\u6280\u672f\u6211\u662f\u5927\u725b\uff09\uff0c\u53e6\u4e00\u90e8\u5206\u5219\u662f\u5bf9\u67d0\u9879\u6280\u672f\u7684\u793e\u7fa4\u5f62\u6210\u4e86\u4e00\u4e2a\u56fe\u50cf\uff0c\u5e0c\u671b\u522b\u4eba\u7528\u8fd9\u4e2a\u56fe\u50cf\u6765\u63cf\u8ff0\u81ea\u5df1\u548c\u8ba4\u540c\u81ea\u5df1\u3002

\n

\u867d\u7136\u8fd9\u79cd\u5fc3\u6001\u4e5f\u8ba9\u6211\u83b7\u5f97\u4e86\u4e00\u4e9b\u6709\u8da3\u548c\u6709\u7528\u7684\u7ecf\u9a8c\uff0c\u6bd4\u5982 Emacs\uff0c\u4f46\u603b\u5730\u8bf4\u6765\u662f\u8ba9\u6211\u6d6a\u8d39\u4e86\u592a\u591a\u7684\u65f6\u95f4\u5728\u8fc7\u5404\u79cd tutorial \u548c\u5199 hello world \u4e0a\u3002Language hopping \u7684\u7ed3\u679c\u5c31\u662f\u59cb\u7ec8\u65e0\u6cd5\u6df1\u5165\u94bb\u7814\u4e00\u4e2a\u4e1c\u897f\uff0c\u4e5f\u5c31\u4e0d\u77e5\u9053\u5b83\u80fd\u5e72\u4ec0\u4e48\uff0c\u5b83\u7684\u5c40\u9650\u5728\u54ea\u91cc\u3002

\n

\u8fd9\u6837\u770b\u6765\uff0cEmacs \u7684\u5389\u5bb3\u4e4b\u5904\u5728\u4e8e\u201c\u4ece\u5165\u95e8\u5230\u7cbe\u901a\u201d\uff08\u7cbe\u901a\u662f\u4e2a\u5883\u754c\uff0c\u8fd9\u8f88\u5b50\u90fd\u4e0d\u53ef\u80fd\u7cbe\u901a\u7684\uff09\u63d0\u4f9b\u4e86\u4e00\u6761\u8fde\u7eed\u800c\u65e0\u7a77\u5c3d\u7684\u5b66\u4e60\u9014\u5f84\uff0c\u53ea\u8981\u662f\u548c\u6587\u672c\u6709\u5173\u7684\u95ee\u9898\uff0c\u90fd\u53ef\u4ee5\u5c1d\u8bd5\u7740\u7528\u5b83\u53bb\u89e3\u51b3\uff0c\u5e76\u4e14\u5728\u8fd9\u4e2a\u8fc7\u7a0b\u4e2d\u53ef\u80fd\u53c8\u5b66\u5230\u4e86\u4e00\u70b9\u65b0\u4e1c\u897f\u3002Python \u4e5f\u662f\u7c7b\u4f3c\uff0c\u5165\u95e8\u95e8\u69db\u4f4e\uff0c\u5929\u82b1\u677f\u51e0\u4e4e\u65e0\u9650\u9ad8\uff0c\u4f46\u4e2d\u95f4\u6bcf\u4e00\u5c42\u90fd\u53ef\u4ee5\u63a2\u7d22\u3002

\n

\u800c Ruby \u7684\u95ee\u9898\u5927\u6982\u5c31\u662f\u8fd9\u4e48\u591a\u5e74 Rails \u72ec\u9886\u98ce\u9a9a\uff0c\u57fa\u672c\u4e0a\u8981\u6c42\u5b66\u4e60\u8005\u5199\u5b8c hello world \u548c fizzbuzz \u4e4b\u540e\u5c31\u5f00\u59cb\u7814\u7a76\u5143\u7f16\u7a0b\u3001DSL \u548c Rails \u7684\u5404\u79cd\u4ee4\u4eba\u773c\u82b1\u7f2d\u4e71\u7684\u5b9e\u73b0\u6280\u5de7\uff0c\u7f3a\u4e4f\u66f4\u5e7f\u6cdb\u7684\u95ee\u9898\u57df\u548c\u8fde\u7eed\u7684\u5b66\u4e60\u8def\u5f84\u3002

\n

\u4f5c\u4e3a\u6bd4\u8f83\u65b0\u7684\u8bed\u8a00\uff0cRacket \u548c Roku \u4e5f\u6709\u7c7b\u4f3c\u7684\u95ee\u9898\uff08\u4e0d\u77e5\u9053\u4e3a\u4ec0\u4e48\u6211\u5bf9 R \u5f00\u5934\u7684\u8bed\u8a00\u6bd4\u8f83\u611f\u5174\u8da3\uff09\u3002\u4e0d\u8fc7\u6211\u8fd8\u662f\u60f3\u5b66\u597d Ruby \u53bb\u7ed9 DHH \u6253\u5de5\u7684\uff0c\u5c3d\u7ba1\u53ea\u4f1a fizzbuzz \uff08\u54ed

\n" }, { "author": { "url": "member/fxjson", "name": "fxjson", "avatar": "https://cdn.v2ex.com/gravatar/3699e3a269b5b051942d2e082a8b2ab2?s=73&d=retro" }, "url": "t/682185", "date_modified": "2020-06-16T18:15:47+00:00", "content_html": "

\u73a9\u8fc7\u4e00\u6bb5\u65f6\u95f4\u7684 ror, \u611f\u89c9\u633a\u723d\uff0c\u7279\u522b\u662f\u547d\u4ee4\u884c\u5de5\u5177\uff0c\u73b0\u5728\u601d\u60f3\u88ab php,python \u6284\u7684\u5dee\u4e0d\u591a\u4e86\uff0c\u770b\u770b ruby china \u793e\u533a\uff0c\u8fd8\u6709 v2 \u7684 ruby \u8282\u70b9\uff0c\u5f80\u65e5\u4e0d\u518d\uff0c\u597d\u53ef\u60dc\uff0c\u5e0c\u671b ruby3*3 \u80fd\u8d77\u6765\u5427

\n", "date_published": "2020-06-16T14:09:01+00:00", "title": "ruby,\u4e00\u4ee3\u4f18\u79c0\u8bed\u8a00\u5c31\u8fd9\u6837\u9668\u843d\u4e86\u5417\uff1f", "id": "t/682185" }, { "author": { "url": "member/yykrlc", "name": "yykrlc", "avatar": "https://cdn.v2ex.com/avatar/43f1/ddfc/236979_large.png?m=1498269608" }, "url": "t/681993", "title": "ruby \u7684 \"a\" \u548c :a \u80fd\u8f6c\u6362\u5417", "id": "t/681993", "date_published": "2020-06-16T03:52:34+00:00", "content_html": "ruby \u7684 x = {\"a\": 1 \"b\": 2}
y = 'b'
> x[y]
=> nil
> x[:b]
=> 2
\u600e\u4e48\u529e\uff0c\u6211\u7684\u53d8\u91cf\u662f\u5b57\u7b26\u4e32" }, { "author": { "url": "member/freeduke", "name": "freeduke", "avatar": "https://cdn.v2ex.com/gravatar/f1b41b728e2a66968a7b641af3d295a8?s=73&d=retro" }, "url": "t/674972", "date_modified": "2020-05-24T10:59:44+00:00", "content_html": "\u670d\u52a1\u5668\u5728\u56fd\u5185\uff0c\u817e\u8baf\u4e91 1C 2G\uff0ccentOS7\uff0c
\u8bf7\u8054\u7cfb\u6211\u7684 yduke # qq.com", "date_published": "2020-05-24T10:59:09+00:00", "title": "\u6c42\u5927\u4f6c\u5e2e\u5b89\u88c5\u4e00\u4e2a mastodon\uff0c\u6709\u507f\uff01", "id": "t/674972" }, { "author": { "url": "member/ColinChang", "name": "ColinChang", "avatar": "https://cdn.v2ex.com/gravatar/c855c9f9f87fa23c43efd537baf4710b?s=73&d=retro" }, "url": "t/651562", "date_modified": "2020-03-10T08:36:28+00:00", "content_html": "\u6211\u7279\u522b\u559c\u6b22\u7528 notepad ssh \u5230\u5b66\u6821 linux \u670d\u52a1\u5668\u64b8\u4ee3\u7801
\u6700\u8fd1\u5199\u811a\u672c\u8bed\u8a00\uff08 perl,ruby \uff09\u7684\u65f6\u5019\uff0c\u7ecf\u5e38\u4f1a\u62a5\u5404\u79cd\u7a00\u5947\u53e4\u602a\u7684\u9519\u3002\u603b\u7ed3\u4e00\u4e0b\u5fc3\u5f97\u3002


[/img]
\u770b\u8d77\u6765\u5f88\u6b63\u5e38\uff0c\u4f46\u662f\u9519\u8bef\u63d0\u793a\u627e\u4e0d\u5230\u6587\u4ef6\uff0c\u6240\u4ee5\u6000\u7591\u662f\u7b2c\u4e00\u884c\u6ca1\u6709\u6210\u529f\u8c03\u7528 ruby\u3002
\u8bd5\u8bd5\u7528 ruby \u624b\u52a8\u8fd0\u884c\u811a\u672c\uff0c\u679c\u7136\u63d0\u793a shellbang \u6709\u4e00\u4e2a\\r\uff0c\u53ef\u80fd\u4f1a\u9020\u6210\u95ee\u9898\u3002

[img][/img]
\u8f6c\u6210 16 \u8fdb\u5236\u770b\u4e0b\uff0c\u67e5\u4e86\u4e0b ASCII \u5b57\u7b26 16 \u8fdb\u5236\u7684\u4ee3\u7801\uff0c\u679c\u7136\u4e00\u5806 CR \u7b26 \\r 0x0d,windows \u7cfb\u7edf\u7684\u6362\u884c\u662f\\r\\n\uff0c\u5148\u56de\u8f66(carriage return)\uff0c\u518d\u6362\u884c(line feed)\uff0c\u53ef\u4ee5\u8ffd\u6eaf\u5230\u6253\u5b57\u673a\u65f6\u4ee3\u3002\u800c linux \u76f4\u63a5\\n \u5c31\u6362\u884c\u4e86

[img][/img]
\u6700\u7b80\u5355\u65b9\u6cd5\uff0c\u5199\u4e2a\u811a\u672c\u4e8c\u8fdb\u5236\u6253\u5f00\u7a0b\u5e8f\u6587\u672c\uff0c\u5220\u9664\u6240\u6709 0d\u3002\u8bb0\u5f97\u53bb\u5e74\u4e0a socket \u7f16\u7a0b\u7684\u65f6\u5019\uff0c\u8001\u5e08\u7b2c\u4e00\u4e2a\u6559\u7684\u7a0b\u5e8f\u5c31\u662f\u5728 linux \u548c windows \u4e4b\u95f4\u8f6c\u6362\u6587\u672c\uff0c\u5c31\u662f\u8fd9\u6837\u5b9e\u73b0\u7684

\u4f46\u662f\u8fd9\u6837\u7684\u8bdd\uff0c\u6bcf\u6b21\u5199\u4e24\u884c\u60f3\u6d4b\u8bd5\u7684\u65f6\u5019\uff0c\u5c31\u5f97\u624b\u52a8\u8fd0\u884c\u4e0b\u8f6c\u6362\u7a0b\u5e8f\uff0c\u989d\u5916\u589e\u52a0\u4e86\u8d1f\u62c5\uff08\u6211\u4fdd\u5b58 ctrl S \u90fd\u61d2\u5f97\u6309\uff0c\u7528\u7684\u662f notepad++\u7684\u7a97\u53e3\u5931\u53bb\u7126\u70b9\u81ea\u52a8\u4fdd\u5b58\u3002\u3002\u3002\uff09

\u4f46\u6211\u53c8\u4e0d\u60f3\u7528 ssh \u5ba2\u6237\u7aef\u7684\u5783\u573e\u7f16\u8f91\u5668\uff0c\u4e8e\u662f\u5c06\u5c31\u4e00\u4e0b\uff0c\u624b\u52a8\u518d linux \u91cc\u7528 vim \u6572\u7b2c\u4e00\u884c\uff0c\u5269\u4e0b\u7684 notepad++ ssh \u5c31\u53ef\u4ee5\u7ee7\u7eed\u5199\u4e86


\u8fd8\u6709\u4ec0\u4e48\u5751\uff0c\u60f3\u60f3\u7ee7\u7eed\u7801\u5b57", "date_published": "2020-03-10T08:28:08+00:00", "title": "notepad++ ssh \u4e00\u4e9b\u4e2a\u5c0f\u5751", "id": "t/651562" }, { "author": { "url": "member/junho", "name": "junho", "avatar": "https://cdn.v2ex.com/gravatar/14296d63a2229450e57bc3a7eaba685a?s=73&d=retro" }, "url": "t/602859", "title": "\u6709\u4ec0\u4e48\u597d\u7684\u65b9\u6cd5/IDE \u9605\u8bfb Gem \u5e93\u7684\u6e90\u7801\uff1f", "id": "t/602859", "date_published": "2019-09-21T08:36:08+00:00", "content_html": "\u5e73\u65f6\u5f00\u53d1\u4f7f\u7528 CocoaPod \u6bd4\u8f83\u591a\uff0c\u6253\u7b97\u770b\u4e0b\u6e90\u7801\u4ee5\u4fbf\u66f4\u597d\u5730\u8f85\u52a9\u5f00\u53d1\u3002
\u5df2\u7ecf\u5b66\u4e86 Ruby \u7684\u4e00\u4e9b\u57fa\u7840\u77e5\u8bc6\uff0c\u4f46\u662f\u9605\u8bfb\u8fc7\u7a0b\u4e2d\u6ca1\u6709 IDE \u5de5\u5177\uff0c\u4e0d\u80fd\u8df3\u8f6c\u67e5\u770b\u65b9\u6cd5\u8c03\u7528\u5565\u7684\u5f88\u4e0d\u65b9\u4fbf
\u8bf7\u95ee\u4e0b\u6709\u6ca1\u6709\u4ec0\u4e48 IDE\uff0c\u53ef\u4ee5\u628a\u6574\u4e2a\u5de5\u7a0b\u5bfc\u8fdb\u53bb\u65b9\u4fbf\u770b\u6e90\u7801\u7684\uff1f" }, { "author": { "url": "member/Kronos", "name": "Kronos", "avatar": "https://cdn.v2ex.com/gravatar/9e648736233d9b00e52d53278ae40f14?s=73&d=retro" }, "url": "t/596019", "title": "\u95ee\u4e00\u4e2a ruby \u7684\u95ee\u9898", "id": "t/596019", "date_published": "2019-08-28T13:12:18+00:00", "content_html": "

ruby \u4e2d\u7684>>\u4ec0\u4e48\u610f\u601d\uff1f 2880000000 >> 10 \u8ba1\u7b97\u7684\u7ed3\u679c\u662f\u591a\u5c11\uff1f\n\u4e4b\u524d\u4e5f\u6ca1\u6709\u63a5\u89e6\u8fc7 ruby\uff0c\u4eca\u5929\u770b\u4e86\u4e00\u4e2a ruby \u5904\u7406\u6570\u636e\u7684\u811a\u672c\uff0c\u524d\u9762\u770b\u5f97\u7565\u61c2\uff0c\u5230>>\u8fd9\u5c31\u5361\u4f4f\u4e86 \u8001\u54e5\u4eec\uff0c\u5e2e\u5e2e\u5fd9\u89e3\u91ca\u4e00\u4e0b\uff1a\uff09

\n" }, { "author": { "url": "member/chinesestudio", "name": "chinesestudio", "avatar": "https://cdn.v2ex.com/avatar/9191/2c04/371581_large.png?m=1556562307" }, "url": "t/594942", "title": "\u7528 discourse \u642d\u4e86\u4e2a\u8bba\u575b \u6c42\u6d4b\u8bd5", "id": "t/594942", "date_published": "2019-08-25T09:19:50+00:00", "content_html": "

\u5927\u5bb6\u53ef\u4ee5\u6765\u6d4b\u8bd5\u611f\u53d7\u4e00\u4e0b

\n

\u5305\u62ec\u6709\u5584\u7684\u538b\u6d4b

\n

\u8bba\u575b\u6ca1\u5565\u5185\u5bb9

\n

\u7a0b\u5e8f\u733f\u4e5f\u4e0d\u662f\u76ee\u6807\u7528\u6237

\n

\u6240\u4ee5\u522b\u8ba4\u4e3a\u662f\u63a8\u5e7f\u5c31\u884c

\n

https://forums.taosky.com

\n

\u8fdc\u7a0b cloudflare nginx frps

\n

\u672c\u5730 frpc discourse

\n

\u6d4b\u8bd5\u9636\u6bb5

\n

\u53ea\u6c42\u80fd\u7528 \u901f\u5ea6\u5c31\u522b\u6307\u671b\u4e86\u592a\u5feb

\n

\u4e2d\u6587\u5206\u8bcd\u8fd8\u662f\u6ca1\u5b8c\u5584

\n

\u5bfc\u81f4\u641c\u7d22\u548c\u654f\u611f\u8bcd\u8fc7\u6ee4\u6548\u679c\u4e00\u822c

\n

\u5176\u4ed6\u95ee\u9898\u6162\u6162\u53d1\u73b0\u89e3\u51b3

\n

\u5148\u8c22\u5566

\n

discourse \u7684\u95ee\u9898\u4e5f\u53ef\u4ee5\u95ee\u6211

\n" }, { "author": { "url": "member/jfry", "name": "jfry", "avatar": "https://cdn.v2ex.com/gravatar/55b09f9dd3b9f2d95c3fc520155298fc?s=73&d=retro" }, "url": "t/594596", "date_modified": "2019-08-23T11:05:08+00:00", "content_html": "

\u5df2\u7ecf\u5b9e\u73b0\u4e86\u4e00\u4e9b\u57fa\u672c\u7684\u529f\u80fd\u4e86\uff0c\u4f46\u662f\u8fd8\u6709\u5f88\u591a\u5f85\u5b8c\u5584\u548c\u6539\u8fdb\u7684\u5730\u65b9\uff0c\u627e\u611f\u5174\u8da3\u7684\u5c0f\u4f19\u4f34\u4e00\u8d77\u6765\u5f00\u53d1~

\n

\u4e00\u4e2a\u6bd4\u8f83\u5f53\u524d\u63d0\u4ea4\u548c\u4e0a\u6b21\u63d0\u4ea4\u4fee\u6539\u7684\u4ee3\u7801\u7684\u8986\u76d6\u7387\u7684\u4f8b\u5b50\uff1a

\n
$ incrcov HEAD^ HEAD\n\n+----------------+-----------+-------------+---------------+---------------+--------------+\n| Path | Method | Total Lines | Covered Lines | Coverage Rate | Missed Lines |\n+----------------+-----------+-------------+---------------+---------------+--------------+\n| app/demo2.rb:6 | say_world | 2 | 1 | 50.0% | 7 |\n+----------------+-----------+-------------+---------------+---------------+--------------+\nOverall incremental test coverage: 75.0%\nNumber of updated methods: 2\nNumber of low test coverage(<90%) methods: 1\n
\n

\u9879\u76ee\u5730\u5740\uff1a https://github.com/toaco/incrcov

\n", "date_published": "2019-08-23T11:02:15+00:00", "title": "\u627e\u5c0f\u4f19\u4f34\u4e00\u8d77\u5f00\u53d1\u548c\u5b8c\u5584\u4e00\u4e2a Ruby \u589e\u91cf\u4ee3\u7801\u8986\u76d6\u7387\u7edf\u8ba1\u5de5\u5177", "id": "t/594596" }, { "author": { "url": "member/ycz0926", "name": "ycz0926", "avatar": "https://cdn.v2ex.com/avatar/8736/3191/212962_large.png?m=1568379868" }, "url": "t/581441", "title": "\u90fd\u5728\u8bf4\u6291\u90c1\uff0c\u6211\u4eec\u5b66\u4e00\u4e0b ruby \u5427\uff0c\u4e00\u95e8\u8ba9\u4f60\u5feb\u4e50\u7684\u8bed\u8a00", "id": "t/581441", "date_published": "2019-07-09T11:01:33+00:00", "content_html": "

https://rubymonk.com/

\n" }, { "author": { "url": "member/TangMonk", "name": "TangMonk", "avatar": "https://cdn.v2ex.com/avatar/c5f1/ae9e/55793_large.png?m=1644466105" }, "url": "t/579758", "title": "ruby2.6 \u7684 jit \u5927\u5bb6\u611f\u89c9\u600e\u4e48\u6837\uff1f", "id": "t/579758", "date_published": "2019-07-03T12:18:58+00:00", "content_html": "" }, { "author": { "url": "member/hujianxin", "name": "hujianxin", "avatar": "https://cdn.v2ex.com/avatar/9024/ae2d/97887_large.png?m=1555229655" }, "url": "t/510051", "title": "\u5728 one-liner \u6587\u672c\u5904\u7406\u65b9\u9762\uff0c ruby \u6bd4 perl \u8981\u900a\u8272\u5417\uff1f", "id": "t/510051", "date_published": "2018-11-21T07:29:13+00:00", "content_html": "

\u4e4b\u524d\u6ca1\u63a5\u89e6\u8fc7 ruby\uff0c\u6240\u4ee5\u8fc7\u6765\u8bf7\u6559\u5927\u4f6c\uff0c\u8c22\u8c22

\n" }, { "author": { "url": "member/scottverne", "name": "scottverne", "avatar": "https://cdn.v2ex.com/gravatar/0b00a68b843a931c6b1c225f8ea17a22?s=73&d=retro" }, "url": "t/505120", "title": "\u4f7f\u7528 ruby \u5199\u4e86\u4e00\u4e2a\u5468\u62a5\u7cfb\u7edf", "id": "t/505120", "date_published": "2018-11-06T10:48:21+00:00", "content_html": "

\u5927\u5bb6\u53ef\u4ee5\u4f53\u9a8c http://www.weeklyreport.info/scottverne/2018/11/1

\n

\u4f7f\u7528 sinatra \u6846\u67b6\u5f00\u53d1\u7684\u3002

\n

\"\"

\n

github \u5728 https://github.com/weeklyreportinfo/weeklyreportinfo

\n" }, { "author": { "url": "member/asensio", "name": "asensio", "avatar": "https://cdn.v2ex.com/avatar/f413/558b/253904_large.png?m=1702800353" }, "url": "t/489122", "title": "ruby \u7684 devkit \u5b89\u88c5", "id": "t/489122", "date_published": "2018-09-13T14:11:54+00:00", "content_html": "

\u5b89\u88c5 Ruby \u65f6\uff0c\u5b98\u7f51( https://rubyinstaller.org/downloads/)\u7ed9\u4e86 WITH DEVKIT \u7684 ruby \u5b89\u88c5\u5305\uff0c \u53ef\u662f\u6211\u5168\u7a0b\u5b89\u88c5\u5b8c\u540e\uff0c\u8fd8\u662f\u53d1\u73b0 Devkit \u6ca1\u6709\u88ab\u5b89\u88c5\u554a\uff1f

\n

\u201c WITH DEVKIT \u201d\u662f\u5565\u610f\u601d\u554a\uff1f

\n" }, { "author": { "url": "member/SimbaPeng", "name": "SimbaPeng", "avatar": "https://cdn.v2ex.com/gravatar/644f3f438e1280eb32e78f1aa72929f6?s=73&d=retro" }, "url": "t/421095", "title": "\u603b\u542c\u4eba\u8bf4 ruby \u4ee3\u7801\u5199\u8d77\u6765\u5f88\u723d\uff0c\u6709\u591a\u723d\uff1f\u600e\u4e48\u4e2a\u723d\u6cd5\uff1f", "id": "t/421095", "date_published": "2018-01-08T08:39:29+00:00", "content_html": "" }, { "author": { "url": "member/iosGong", "name": "iosGong", "avatar": "https://cdn.v2ex.com/gravatar/47669605f2679cbcda084ae35bb53696?s=73&d=retro" }, "url": "t/389303", "title": "RubyGems \u6ce8\u518c\u4e0d\u4e86\u7684\uff1f", "id": "t/389303", "date_published": "2017-09-08T13:46:32+00:00", "content_html": "

\u6ce8\u518c\u4e4b\u540e\uff0c\u9a8c\u8bc1\u90ae\u7bb1\uff0c\u5728\u767b\u5f55\u9875\u8fd8\u662f\u63d0\u9192\u9a8c\u8bc1\u90ae\u7bb1\uff0c\u4ec0\u4e48\u9b3c\uff1f\uff1f\uff1f

\n" }, { "author": { "url": "member/syhsyh9696", "name": "syhsyh9696", "avatar": "https://cdn.v2ex.com/avatar/49d9/209e/149313_large.png?m=1657100198" }, "url": "t/345083", "title": "Ruby \u7834\u73af\u65b9\u6cd5\u4e3a\u4ec0\u4e48\u6bd4\u975e\u7834\u574f\u65b9\u6cd5\u6162\u4e00\u4e9b\uff1f", "id": "t/345083", "date_published": "2017-03-05T08:24:33+00:00", "content_html": "

\u505a leetcode \u7684\u65f6\u5019\u6211\u53d1\u73b0

\n

nums.sort! \u660e\u663e\u8981\u6bd4 nums = nums.sort \u8981\u6162 10ms

\n

\u8fd9\u662f\u4e3a\u4ec0\u4e48\u5462\uff1f sort!\u7684\u64cd\u4f5c\u66f4\u591a\uff1f\u867d\u7136 sort!\u5199\u8d77\u6765\u683c\u5916\u7684\u65b9\u4fbf\uff0c\u4f46\u662f\u5403\u4e86\u5f88\u591a\u65f6\u95f4\u7684\u4e8f\u3002

\n" }, { "author": { "url": "member/cosmosz", "name": "cosmosz", "avatar": "https://cdn.v2ex.com/gravatar/bfda0b5cb0c413c429d2851ba8dbcf7f?s=73&d=retro" }, "url": "t/338415", "title": "Ruby Conference 2017 AU", "id": "t/338415", "date_published": "2017-02-06T04:37:29+00:00", "content_html": "

\u8bf7\u95ee\u6709\u4eba\u53bb\u561b\uff1f

\n

\u6211\u5728\u6089\u5c3c\uff0c Ruby On Rails Backend \u5f00\u53d1\u3002

\n

\u6709\u5174\u8da3\u7684\u53ef\u4ee5\u4e00\u8d77\u4ea4\u6d41\u4e0b\u3002

\n" }, { "author": { "url": "member/Gem", "name": "Gem", "avatar": "https://cdn.v2ex.com/gravatar/4506e57d77d4bba333eaa2c9ba89551c?s=73&d=retro" }, "url": "t/331493", "date_modified": "2016-12-31T13:51:22+00:00", "content_html": "\u73b0\u5728 ruby \u4e3b\u8981\u5728 web \u5f00\u53d1\u65b9\u9762\uff0c python \u4e0d\u4f46\u5728 web \u65b9\u9762\uff0c\u5728\u5176\u4ed6\u65b9\u9762\u4e5f\u591a\u6709\u5efa\u6811\uff0c\u5982\u679c\u8bf4\u6027\u80fd\u65b9\u9762\uff0c\u90fd\u662f\u811a\u672c\u8bed\u8a00\uff0c ruby \u4e5f\u6ca1\u5dee\u591a\u5c11\u5427\uff1f\u5728\u5199\u6cd5\u65b9\u9762\uff0c\uff08\u7eaf OOP + FP \u5473\u9053\uff09\uff0c ruby \u5199\u8d77\u6765\uff0c\u4e2a\u4eba\u611f\u89c9\u8fd8\u662f\u8981\u6bd4 python \u6d41\u7545\u4e00\u4e9b\u7684\u3002", "date_published": "2016-12-31T12:58:16+00:00", "title": "ruby \u8fd9\u4e48\u4f18\u96c5\u7684\u8bed\u8a00\uff0c\u600e\u4e48\u6ca1\u6709\u50cf python \u8fd9\u6837\u6d41\u884c\u5f00\u6765\uff1f", "id": "t/331493" }, { "author": { "url": "member/rockllei", "name": "rockllei", "avatar": "https://cdn.v2ex.com/avatar/4916/ba26/40887_large.png?m=1482224375" }, "url": "t/313785", "title": "Ruby \u4e2d Singleton \u65b9\u6cd5\u7684\u53e6\u4e00\u79cd\u7406\u89e3\u65b9\u5f0f", "id": "t/313785", "date_published": "2016-10-19T02:34:21+00:00", "content_html": "

Ruby \u4e2d\u7684 Singleton \u65b9\u6cd5\u662f Ruby \u4e2d\u4e00\u4e2a\u91cd\u8981\u7684\u77e5\u8bc6\u70b9\uff0c\u4e5f\u662f\u505a Ruby \u5143\u7f16\u7a0b\u7684\u4e00\u4e2a\u91cd\u8981\u6280\u5de7\u3002\n\u7b80\u5355\u7684\u8bf4\u5c31\u662f\u5728 Ruby \u4e2d\u4efb\u4f55\u81ea\u5b9a\u4e49\u7c7b\u90fd\u662f Class \u8fd9\u4e2a\u7c7b\u7684\u4e00\u4e2a\u5b9e\u4f8b\uff0c\u6240\u4ee5 Singleton \u65b9\u6cd5\u5176\u5b9e\u5c31\u662f\u4e00\u4e2a\u5b9e\u4f8b\u6240\u62e5\u6709\u7684\u65b9\u6cd5\uff0c\u6bd4\u5982:

\n
a = \"hi\"\n\ndef a.you\n \"hi, you\"\nend\n\na.you # => hi, you\n\n\"hello\".you # => undefined method 'you'\n
\n

\u4e0a\u9762\u7684 a.you \u65b9\u6cd5\u5c31\u662f a \u8fd9\u4e2a\u5b57\u7b26\u4e32\u5b9e\u4f8b\u7684 Singleton Method \u3002

\n

\u540c\u6837\u5982\u679c\u62ff\u6211\u4eec\u6700\u719f\u6089\u7684\u7c7b\u4e3e\u4f8b\u5b50\u7684\u8bdd\u5c31\u662f\uff1a

\n
class A\n def self.hi\n 'hi A'\n end\nend\n\nA.hi # => hi A\n
\n

\u4e0a\u9762\u7684\u5b9a\u4e49\u65b9\u6cd5\u6240\u6709\u7684\u540c\u5b66\u5e94\u8be5\u90fd\u77e5\u9053\uff0c\u5176\u5b9e\u5c31\u662f\u7c7b\u65b9\u6cd5\u7684\u5b9a\u4e49\uff0c\u5728 Ruby \u4e2d\u7c7b\u65b9\u6cd5\u5176\u5b9e\u5c31\u662f\u7c7b\u7684 Singleton Method \uff0c\u5c31\u50cf\u4e0a\u9762\u8bf4\u7684\u56e0\u4e3a A \u4e5f\u662f Class \u8fd9\u4e2a\u7c7b\u7684\u4e00\u4e2a\u5b9e\u4f8b\uff08\u901a\u8fc7 A.class \u5c31\u53ef\u4ee5\u77e5\u9053\uff09\uff0c\u6240\u4ee5\uff0c\u5176\u5b9e\u4e0a\u9762\u7684\u65b9\u6cd5\u4e5f\u53ef\u4ee5\u8fd9\u6837\u5b9a\u4e49\uff1a

\n
class A\nend\n\ndef A.hi\n 'hi A'\nend\n\nA.hi # => hi A\n
\n

\u8fd9\u6837\u7684\u8bdd\uff0c\u5c31\u548c\u4e0a\u9762\u5b57\u7b26\u4e32 a \u7684\u6548\u679c\u4e00\u6837\uff0c\u5c31\u66f4\u5bb9\u7406\u89e3\u4e86\u3002\n\u6240\u4ee5\u5173\u952e\u662f\u7406\u89e3\u6211\u4eec\u6240\u5b9a\u4e49\u7684\u7c7b\u4e5f\u662f Class \u8fd9\u4e2a\u7c7b\u7684\u4e00\u4e2a\u5b9e\u4f8b\uff0c\u8fd9\u662f\u5173\u952e\u3002

\n
\n

\u5176\u5b9e\u6211\u60f3\u8bf4\u7684\uff0c\u4e0b\u9762\u624d\u662f\u5173\u952e\uff0c

\n

\u86cb\u4eba\u7f51 http://eggman.tv \u7684\u6700\u65b0\u7cfb\u5217\u5927\u8bfe\u7a0b<Ruby \u5143\u7f16\u7a0b=\"\">\u5df2\u7ecf\u5f00\u5751\u4e86\uff0c\u4ece\u4eca\u5929\u5f00\u59cb\u4f1a\u9646\u7eed\u66f4\u65b0\uff0c\u7b2c\u4e00\u8282\u89c6\u9891\u8bfe\u4ef6<Ruby \u5143\u7f16\u7a0b\u7684\u4ecb\u7ecd\u548c\u4f7f\u7528\u573a\u666f=\"\">\u5df2\u7ecf\u653e\u51fa\uff0c\u514d\u8d39\u7684\uff0c http://eggman.tv/c/s-ruby-meta-programming \uff0c\u8ba1\u5212\u6bcf\u5468\u66f4\u65b0\u4e24\u671f\uff0c\u4e0a\u9762\u8bb2\u8ff0\u7684\u662f\u8bfe\u4ef6\u4e00\u90e8\u5206\u5185\u5bb9\uff0c\u6211\u4eec\u8ba1\u5212\u4f1a\u5728\u6574\u4e2a\u8bfe\u4ef6\u4e2d\u4e3a\u5927\u5bb6\u8bb2\u8ff0\uff1a

\n\n

\u7b49\u7b49\u4f17\u591a\u6df1\u5165\u5185\u5bb9\u7684\u8bb2\u89e3\uff0c\u5f53\u7136\u8fd8\u5305\u62ec\u4f17\u591a\u7684\u5b9e\u4f8b\u6f14\u793a\u548c\u5982\u4f55\u4f7f\u7528\u8fd9\u4e9b\u9ad8\u7ea7\u6280\u5de7\uff0c\u6b22\u8fce\u5404\u4f4d\u5927\u54e5\u5927\u5ac2\u524d\u6765\u652f\u6301\u3002

\n" }, { "author": { "url": "member/xinali", "name": "xinali", "avatar": "https://cdn.v2ex.com/avatar/cc6e/581c/111322_large.png?m=1711442898" }, "url": "t/306641", "title": "\u9700\u8981\u5b66\u4e60 ruby\uff0c\u60f3\u95ee\u73b0\u5728 ruby \u7684\u4e3b\u6d41\u7248\u672c\u662f\u591a\u5c11\uff1f", "id": "t/306641", "date_published": "2016-09-16T11:54:20+00:00", "content_html": "

\u8ddf python \u5dee\u4e0d\u591a\uff0c\u6bd4\u5982 python \u73b0\u5728\u7684\u4e3b\u6d41\u7248\u672c\u662f 2.7 \uff0c\u4e3b\u8981\u7684\u5de5\u5177\u548c\u5e93\u4e5f\u90fd\u96c6\u4e2d\u5728 2.7

\n

\u90a3\u4e48 ruby \u7684\u4e3b\u6d41\u7248\u672c\u5462\uff0c\u4e3b\u8981\u662f\u4e3b\u6d41\u5e93\u554a\uff0c\u5de5\u5177\u4ec0\u4e48\u7684\u6240\u7528\u7684\u7248\u672c

\n" }, { "author": { "url": "member/popu111", "name": "popu111", "avatar": "https://cdn.v2ex.com/avatar/ffdd/1df8/59927_large.png?m=1491693344" }, "url": "t/290915", "title": "Ruby \u7684\u5185\u5b58\u5360\u7528\u6781\u9650\uff1f", "id": "t/290915", "date_published": "2016-07-07T08:42:12+00:00", "content_html": "

\u6700\u8fd1\u6709\u4e9b\u95f2\u8bd5\u7740\u4f5c\u4e2a\u6b7b\uff0c\u5728 irb \u91cc\u6267\u884cr = (1..99999999999999).to_a

\n

\u672c\u6765\u4ee5\u4e3a\u5f88\u5feb\u5c31\u80fd\u628a\u5185\u5b58\u5360\u5230 2G \u6765\u7740\uff0c\u7ed3\u679c\u624d 500M \u5c31\u62a5\u9519\u4e86

\n

\"Image

\n

\"Image

\n

\uff08\u6709\u4e09\u4e2a\u8fdb\u7a0b\uff0c\u662f\u6211\u540e\u6765\u53c8\u5f00\u4e86\u4fe9\uff0c\u4f46\u662f\u8fd9\u6b21 700M \u624d\u62a5\u9519\uff09

\n

\u6240\u4ee5\u73b0\u5728\u95ee\u9898\u6765\u4e86\uff0c\u8fd9\u5230\u5e95\u5565\u60c5\u51b5\uff1f

\n" }, { "author": { "url": "member/shyling", "name": "shyling", "avatar": "https://cdn.v2ex.com/avatar/c129/6c1a/142212_large.png?m=1455339718" }, "url": "t/285989", "title": "Ruby \u5199\u4e86\u4e00\u4e2a\u547d\u4ee4\u884c\u706b\u8f66\u7968\u67e5\u770b\u5668", "id": "t/285989", "date_published": "2016-06-15T10:31:04+00:00", "content_html": "

\u6700\u8fd1\u8ff7\u4e0a\u4e86 Ruby \u5450\uff0c\u5728 Python \u533a\u770b\u5230\u4e86http://v2ex.com/t/284909\n\u987a\u624b\u4e5f\u7528 Ruby \u5199\u4e86\u4e00\u4e2a\uff0c\u53c2\u8003\u4e86\u90e8\u5206\u4ee3\u7801\u3002

\n

\u5730\u5740:github

\n

\"Tickets\"

\n

\u987a\u4fbf\u589e\u52a0\u4e86\u66f4\u65b0 stations.dat \u7684\u529f\u80fd

\n

\u4e0d\u662f\u5f88\u4f1a\u73a9 rubygems \uff0c\u5c31\u4e0d\u8003\u8651\u4e0a\u4f20\u4ec0\u4e48\u7684\u4e86

\n

\u8bdd\u8bf4\uff0c\u7f16\u7801\u95ee\u9898\u8fd8\u662f\u5f88\u9ebb\u70e6\u554a=-=\n\u5728 windows \u4e0a ARGV \u91cc\u9ed8\u8ba4\u662f GBK \u7f16\u7801\uff0c\u6211\u5728 ssh \u91cc\u7528 arch \u65f6 ARGV \u662f ASCII_8BIT,\u5728\u7535\u8111\u4e0a\u7684 arch \u4e0a\u662f utf-8 \uff0c ARGV \u7684\u5185\u5bb9\u9ed8\u8ba4\u8fd8\u662f frozen \u7684\u3002 Rubinius/JRuby \u4ec0\u4e48\u7684\u8fd8\u6728\u6709\u6d4b\u8bd5

\n

\u6c42 star \u554a\u6c42 star,\u987a\u4fbf\u5982\u679c\u90a3\u91cc\u5199\u7684\u4e0d\u597d\u7684\u8bdd\u6c42\u6307\u70b9\u3002

\n" }, { "author": { "url": "member/mortonnex", "name": "mortonnex", "avatar": "https://cdn.v2ex.com/avatar/67b8/6995/156857_large.png?m=1461910632" }, "url": "t/270657", "title": "\u6709\u8c01\u7528\u8fc7 Ruby \u5199\u7684\u6bd4\u7279\u5e01\u4ea4\u6613\u5e73\u53f0 Peatio,admin \u9762\u677f\u8fdb\u4e0d\u53bb,\u6c42\u6559\u554a\u554a\u554a\u554a\u554a\u554a\u554a", "id": "t/270657", "date_published": "2016-04-13T03:05:03+00:00", "content_html": "

https://github.com/peatio/peatio

\n

\u6309\u7167 readme \u5b89\u88c5\u5230\u6211\u7684 Mac \u4e0a,\u4f7f\u7528\u4ed6\u7ed9\u7684 admin \u5e10\u53f7\u767b\u5f55,\u7ed3\u679c\n\u8fdb\u4e0d\u53bb admin \u7684\u9762\u677f

\n

\u6c42\u89e3\u7b54,\u6709\u94dc\u5e01\u9001\u4e0a~~

\n" }, { "author": { "url": "member/EchoWhale", "name": "EchoWhale", "avatar": "https://cdn.v2ex.com/avatar/ec55/4ba4/162040_large.png?m=1735781838" }, "url": "t/267309", "title": "\u548c\u9694\u58c1\u7684 python \u6bd4\u8d77\u6765\uff0c\u8fd9\u8282\u70b9\u597d\u51b7\u6e05", "id": "t/267309", "date_published": "2016-03-30T04:17:05+00:00", "content_html": "" }, { "author": { "url": "member/rockuw", "name": "rockuw", "avatar": "https://cdn.v2ex.com/gravatar/f0874d863bc2249e2cc43ea4f21f4c5c?s=73&d=retro" }, "url": "t/263451", "title": "\u963f\u91cc\u4e91 OSS Ruby SDK \u5f00\u53d1\u624b\u8bb0", "id": "t/263451", "date_published": "2016-03-14T11:52:57+00:00", "content_html": "

\u963f\u91cc\u4e91 OSS\u662f\u4e00\u4e2a\u5bf9\u8c61\u5b58\u50a8\u670d\u52a1\uff0c\u7c7b\u4f3c\u4e8e Amazon \u7684 S3 \u3002\u76f8\u6bd4\u4e8e\u81ea\u5efa\u5b58\u50a8\uff0c\u4f7f\u7528 OSS \u80fd\u591f\u8fc5\u901f\u5e2e\u60a8\u641e\u5b9a\u5b58\u50a8\uff0c\u5e76\u4e14\u5927\u5927\u5730\u8282\u7701\u6210\u672c\uff0c\u63d0\u5347\u53ef\u9760\u6027\u548c\u5b89\u5168\u6027\u3002

\n\n

\u73b0\u5728\uff0c\u559c\u6b22 Ruby \u7684\u540c\u5b66\u7ec8\u4e8e\u53ef\u4ee5\u4f18\u96c5\u5730\u4f7f\u7528 OSS \u4e86\u3002\u5148\u770b\u770b Rubyist \u5982\u4f55\u4e0a\u4f20\u548c\u4e0b\u8f7d\u6587\u4ef6\u5427\uff1a

\n
require 'aliyun/oss'\nbucket = Aliyun::OSS::Client.new(\n endpoint: 'http://oss-cn-hangzhou.aliyuncs.com',\n access_key_id: 'xxx',\n access_key_secret: 'yyy').get_bucket('bucket')\n\nbucket.put_object('ruby') { |s| s << 'hello world' }\nbucket.get_object('ruby') { |c| puts c }\n\nbucket.put_object('rails', :file => '/tmp/x')\nbucket.get_object('rails', :file => '/tmp/y')\n
\n\n

\u662f\u4e0d\u662f so easy \uff1f OSS SDK for Ruby \u652f\u6301 OSS \u76ee\u524d\u7edd\u5927\u90e8\u5206\u529f\u80fd\uff0c\u4e3b\u8981\u7684 highlights \u5305\u62ec\uff1a

\n\n\n\n

\u4e0b\u9762\u6211\u4eec\u968f\u4fbf\u6311\u51e0\u4e2a\u6765\u804a\u4e00\u804a\uff1a

\n\n

1. iterator \u5f62\u5f0f\u7684\u5217\u8868

\n\n

OSS \u7528\u6237\u5728\u4e00\u4e2a bucket \u4e0b\u53ef\u80fd\u6709\u6210\u5343\u4e0a\u4e07\u7684 objects \uff0c\u6240\u4ee5 OSS \u4e0d\u4f1a\u5c06 object \u5217\u8868\u4e00\u6b21\u6027\u5168\u90e8\u8fd4\u56de\uff0c\u6bcf\u6b21\u6700\u591a\u8fd4\u56de 1000 \u6761\u3002\u5982\u679c\u6211\u8981\u5217\u51fa\u524d 1001 \u4e2a object \u600e\u4e48\u529e\uff1f\u4e00\u822c\u6765\u8bf4\u7528\u6237\u53ef\u80fd\u8981\u8c03\u7528\u4e24\u6b21\u63a5\u53e3\u3002\u4f46\u662f\u5728 ruby \u4e2d\u4f60\u53ea\u9700\u8981\u4e00\u884c\uff1a

\n
bucket.list_objects.take(1001)\n
\n\n

\u518d\u6bd4\u5982\u7528\u6237\u8981\u627e files/\u4e0b\u6587\u4ef6\u540d\u5305\u542b'ruby'\u7684\u6587\u4ef6\uff1a

\n
bucket.list_objects(prefix: 'files/').find { |x| x.key.include?('ruby') }\n
\n\n

\u662f\u4e0d\u662f\u975e\u5e38\u65b9\u4fbf\uff1f

\n\n

2. \u6d41\u5f0f\u4e0a\u4f20

\n\n

\u6d41\u5f0f\u4e0a\u4f20\u5141\u8bb8\u7528\u6237\u52a8\u6001\u5730\u4e00\u8fb9\u751f\u6210\u5185\u5bb9\uff0c\u4e00\u8fb9\u4e0a\u4f20\u5230 OSS \uff0c\u4e0a\u4f20\u7684\u6570\u636e\u53ef\u4ee5 generated on the fly \u3002\u5982\u4e0b\u9762\u7684\u4f8b\u5b50\uff1a

\n
bucket.put_object('numbers') do |stream|\n (1..1_000_000).each { |i| stream << i << "\\n" }\nend\n
\n\n

\u6ce8\u610f\uff1a\u8fd9\u91cc\u5e76\u4e0d\u662f\u8981 100 \u4e07\u4e2a\u6570\u5b57\u90fd\u751f\u6210\u5b8c\u540e\u518d\u53d1\u9001\uff0c\u800c\u662f\u4e00\u8fb9\u751f\u6210\u4e00\u8fb9\u53d1\u9001\u7684\u3002

\n\n

\u8981\u505a\u5230\u4e0a\u9762\u7684\u6548\u679c\u5e76\u4e0d\u5bb9\u6613\uff0c\u8bd5\u60f3\u4e00\u4e0b\uff0cput_object\u8981\u5982\u4f55\u8c03\u7528\u6240\u63a5\u53d7\u7684 block \u53c2\u6570\uff1f\u5982\u679c\u8c03\u7528\u90a3\u4e48 100 \u4e07\u4e2a\u6570\u5b57\u90fd\u4e00\u53e3\u6c14\u751f\u6210\u5b8c\u4e86\uff0c\u6240\u4ee5\uff0c\u5982\u4f55\u80fd\u505a\u5230\u5bf9\u4e00\u4e2a\u51fd\u6570\u8c03\u7528\u4e00\u534a\uff1f \u7b54\u6848\u5c31\u662f\u4f7f\u7528Fiber\u3002

\n
def hello\n puts 'hello'\n Fiber.yield\n puts 'world'\nend\n\ndef world\n fiber = Fiber.new { hello }\n\n puts 'first'\n fiber.resume # puts 'hello'\n puts 'second'\n fiber.resume # puts 'world'\nend\n\nworld\n
\n\n

\u7c7b\u4f3c\u4e0a\u9762\u7684\u4ee3\u7801\uff0cstream#<<\u5185\u6bcf\u63a5\u53d7\u4e00\u90e8\u5206\u5185\u5bb9\uff0c\u4f1a\u5c06\u81ea\u5df1 yield \u51fa\u53bb\uff0c\u8fd9\u6837\u5df2\u7ecf\u63a5\u53d7\u7684\u5185\u5bb9\u5c31\u53ef\u4ee5\u7acb\u5373\u53d1\u9001\u51fa\u53bb\u3002\u6709\u5174\u8da3\u53ef\u4ee5\u67e5\u770bSDK \u4ee3\u7801\u3002

\n\n

3. \u65ad\u70b9\u4e0a\u4f20

\n\n

\u5728\u4e0a\u4f20\u5927\u6587\u4ef6\u65f6\u5982\u679c\u4e2d\u9014\u5931\u8d25\u4e86\uff0c\u8981\u91cd\u65b0\u4e0a\u4f20\u662f\u4e0d\u662f\u5f88\u6cae\u4e27\uff1f\u6709\u4e86\u65ad\u70b9\u4e0a\u4f20\uff0c\u4e2d\u9014\u5931\u8d25\u540e\u53ef\u4ee5\u63a5\u7740\u4e0a\u6b21\u7684\u8fdb\u5ea6\u7ee7\u7eed\u4e0a\u4f20\u3002\u5728 ruby \u4e2d\u53ea\u9700\u8981\uff1a

\n
bucket.resumable_upload('object_key', 'local_file')\n
\n\n

\u65ad\u70b9\u4e0a\u4f20\u4f9d\u8d56\u4e8e OSS \u63d0\u4f9b\u7684 multipart \u529f\u80fd\uff0c\u7c7b\u4f3c\u4e8e\u4e00\u4e2a\u4e8b\u52a1\uff1a

\n\n\n\n

\u53ea\u6709\u6700\u540e\u4e00\u6b65\u6210\u529f\u540e\u6587\u4ef6\u624d\u7b97\u4e0a\u4f20\u6210\u529f\uff0c\u5728\u6b64\u4e4b\u524d\u6587\u4ef6\u5bf9\u7528\u6237\u662f\u4e0d\u53ef\u89c1\u7684\u3002

\n\n

\u6587\u4ef6\u88ab\u4e2d\u65ad\u540e\u5982\u4f55\u6062\u590d\u4e0a\u4f20\uff1f\u5982\u4f55\u77e5\u9053\u54ea\u4e9b parts \u5df2\u7ecf\u4e0a\u4f20\u6210\u529f\uff1f\u8fd9\u9700\u8981\u8bb0\u5f55\u4e8b\u52a1\u7684\u72b6\u6001\u4fe1\u606f\u3002 SDK \u7684\u505a\u6cd5\u662f\u5c06\u8fd9\u4e9b\u4fe1\u606f\uff08\u79f0\u4e3a checkpoint \uff09\u4fdd\u5b58\u5728\u4e00\u4e2a\u672c\u5730\u7684 json \u6587\u4ef6\u4e2d\u3002\u6bcf\u4e0a\u4f20\u5b8c\u4e00\u4e2a part \u5c31\u66f4\u65b0\u4e00\u6b21 checkpoint \u3002\u6062\u590d\u4e0a\u4f20\u65f6\u4ece checkpoint \u6587\u4ef6\u4e2d\u6062\u590d\u4e0a\u4f20\u7684\u8fdb\u5ea6\u3002

\n\n

\u53e6\u5916\u65ad\u70b9\u4e0a\u4f20 /\u4e0b\u8f7d\u4e2d\u4e5f\u5229\u7528\u591a\u7ebf\u7a0b\u5b9e\u73b0\u52a0\u901f\uff0c\u5148\u770b\u7ed3\u679c\uff1a

\n
$ruby tests/test_large_file.rb -n test_large_file_1gb \nRun options: -n test_large_file_1gb --seed 7587\n\n# Running:\n\n user system total real\nUpload with put_object: 20.810000 1.880000 22.690000 ( 62.843336)\nUpload with resumable_upload: 28.720000 9.740000 38.460000 ( 33.963555)\nDownload with get_object: 17.300000 4.550000 21.850000 ( 47.132476)\nDownload with resumable_download: 23.260000 9.530000 32.790000 ( 31.883211)\n
\n\n

Ruby \u6216\u8005 Python \u7684\u591a\u7ebf\u7a0b\u4e00\u76f4\u662f\u4e2a\u201c\u8ff7\u201d\uff0c\u4f46\u662f\u5bf9\u4e8e\u8fd9\u79cd IO \u591a\u573a\u666f\uff0c\u7528\u591a\u7ebf\u7a0b\u6548\u679c\u8fd8\u662f\u5f88\u660e\u663e\u7684\u3002\u56e0\u4e3a\u8fdb\u884c IO \u7684\u6807\u51c6\u5e93\u51fd\u6570\u5728\u9700\u8981\u7b49\u5f85 IO \u65f6\u4f1a\u5c06\u5f53\u524d\u7ebf\u7a0b\u5207\u51fa\u53bb\u3002\u53c2\u8003\uff1a http://yehudakatz.com/2010/08/14/threads-in-ruby-enough-already/

\n\n

\u4e00\u4e2a\u7b80\u5355\u7684 demo

\n\n

\u501f\u52a9 rails \uff0c\u53ef\u4ee5\u5728 15 \u5206\u949f\u5185\u642d\u5efa\u4e00\u4e2aoss \u6587\u4ef6\u7ba1\u7406\u5668\uff0c\u53ef\u4ee5\u67e5\u770b /\u4e0a\u4f20 /\u4e0b\u8f7d\u6587\u4ef6\uff0c\u6548\u679c\u56fe\u5982\u4e0b\uff1a

\n\n

\"QQ20151202_0\"

\n\n

\u66f4\u591a

\n\n\n" }, { "author": { "url": "member/puttin", "name": "puttin", "avatar": "https://cdn.v2ex.com/avatar/5308/7acd/36935_large.png?m=1381394137" }, "url": "t/261840", "date_modified": "2016-03-08T02:13:21+00:00", "content_html": "
    \n
  1. \u6709\u522b\u7684\u53ef\u9009\u9879\u5417?
  2. \n
  3. \u6709\u4ec0\u4e48\u5185\u5e55
  4. \n
\n", "date_published": "2016-03-08T02:12:51+00:00", "title": "\u6dd8\u5b9d RubyGems \u955c\u50cf\u6709\u6bb5\u65f6\u95f4\u6ca1\u540c\u6b65\u4e86", "id": "t/261840" }, { "author": { "url": "member/wentian", "name": "wentian", "avatar": "https://cdn.v2ex.com/avatar/27cf/6860/159783_large.png?m=1485186322" }, "url": "t/261031", "title": "\u4e3a\u4ec0\u4e48 Ruby \u7ed9\u4eba\u4e00\u79cd\u300c\u53ea\u6709 Rails\u300d\u7684\u5370\u8c61?", "id": "t/261031", "date_published": "2016-03-04T02:42:13+00:00", "content_html": "\u8fd9\u5f53\u7136\u662f\u504f\u89c1, \u4f46\u662f\u4e8b\u5b9e\u662f...\r
\u6709\u65f6\u5019\u751a\u81f3\u6709\u4e00\u79cd\u300c\u65e0 Rails \u4e0d Ruby \u300d\u7684\u611f\u89c9" }, { "author": { "url": "member/ming2281", "name": "ming2281", "avatar": "https://cdn.v2ex.com/avatar/fa0e/cdc7/77292_large.png?m=1463581866" }, "url": "t/257497", "title": "Ruby \u4e2d\u6709\u7c7b\u4f3c\u300cPython \u4e2d\u7684 IPython\u300d\u8fd9\u79cd\u300c\u65b9\u4fbf\u4f7f\u7528 Ruby \u89e3\u91ca\u5668\u300d\u7684\u795e\u5668\u5417?", "id": "t/257497", "date_published": "2016-02-18T14:28:03+00:00", "content_html": "" } ] } ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86