当已经会编程时再学习 Python,会面临一个奇怪的问题。你不需要别人解释什么是变量、条件或循环,但仅仅记住更简洁的语法也不够。困难在于恢复——或者说构建——写出在生产环境中自然、可维护且可预测的 Python 所需的判断力。 最有效的进步方式不是压缩一门初学者课程,而是改变学习顺序:从那些影响你设计决策的差异开始,并在可以运行、也可以刻意弄坏的短小示例中逐一练习。 1. 翻译心智模型,而不是逐行翻译代码 从 Java、C#、JavaScript、Go 或 C++ 过来的人,通常首先会把自己已经知道的东西逐字翻译过来。程序能运行,但保留了 Python 不需要的结构、抽象和仪式感。 建议尽早审视以下问题: • 可变性、别名和同一性; • 解包、推导式和惰性迭代; • 作为对象的函数和闭包; • 上下文管理器; • dataclasses 与数据边界; • 能使代码融入语言对象模型的特殊方法。 这些不是冷知识。它们解释了为什么两个正确的实现可能在清晰度和行为上相差很大。 2. 用类型标注设计边界 注解在描述契约时才有价值。一个 Protocol、一个窄化的返回类型或一个定义良好的 callable,可以把策略与其实现分开,让 API 更易于测试。 相反,用注解填满每个局部变量很少能改进设计。一个好的练习是:先定义组件的公共接口,再创建多个满足该接口的实现。这样一来,类型标注就不再是装饰,而成了发现耦合的工具。 3. 根据负载选择并发模型 Python 提供了多种模型,但没有一种放之四海而皆准: • 线程适合阻塞式输入/输出操作; • 进程可以把 CPU 密集型工作隔离开来; • 当许多协作任务大部分时间都在等待时,asyncio 很有用。...
作者 alfredomoraleja
140 次阅读
在将空闲时间投入到
flowtest.io (我希望这将是一项能够彻底改变API测试方式的服务)两个月后,我又重新拾起了
InceptionDB 。 尽管时间已经过去,但我仍清楚地记得当时正在优化性能,心理目标是突破每秒百万次插入(在单个节点上)。百万次并不难超越,但借助AI,我执意要轻松超过百万。实际上,我执意要将其推向更疯狂且不必要的程度,探索各种方案并攻击Inception的不同抽象层。 我重新执行了最后的测试,结果惊人得好像出了什么问题。我选中第一个基准测试: INSERT ,运行它,几乎同时结束。肯定有问题!日志显示在200毫秒内插入了100万条,但我不相信,我以为我关掉了持久化,只工作在内存中,或者没有并发控制导致数据重叠,或者数据发送了但服务器将其丢弃到了/dev/null。 sent: 1000000
took: 182.928406ms
Throughput: 5466619.55 rows/sec
Closing 'col-1779494946505865611'...
http: Server closed 我不信任它,我可以想到一千个理由,但在删除数据库之前设置了一个断点并重新执行。尽管在调试中,结果几乎相同,但现在我有了: /tmp/inceptiondb_bench_811457574/col-1779494946505865611 ,它并非空文件,但只占41MiB。没多想,我将其移动到本地Inception的数据目录,启动它,加载页面,那里就有100万条数据。而且数据似乎也是正确的。 拥有100万文档的基准测试集合 我仍然不相信,创建一个索引,按升序查询,找到了第一个文档 0 。改变顺序,最后一个文档 999999 也在。似乎一切正常。我移开视线,确认自己还在呼吸。 我想到写一篇博客文章,但在此之前重新测试。这次是1000万条。 sent: 10000000
took: 1.078983549s
Throughput: 9267981.90 rows/sec
Closing 'col-1779498339775263815'...
http: Server closed 接近每秒1000万条,估计为410 MiB。显然离磁盘瓶颈还很远,实际测试中磁盘可达9.4 GiB/s,这连5%都不到。 基准测试包含多个测试,用于衡量特定场景的性能: INSERT 、 PATCH 、 REMOVE ,但还有一些我记不清了: INSERTPK 、 INSERTBTREE 、 RETRIEVEBTREE...
作者 gerardooscarjt
968 次阅读
实际上,1970年1月1日那天已经过去了。对许多人来说,这只是一个普通的日子,但对另一些人来说,这是时间的起源,也被称为
Unix 时间 ,即从 1970年1月1日 午夜起经过的秒数。 但这次我不想讨论 Unix 时间,而是想谈谈在编写一些
flowtests 给 Cloudflare 的一个服务时发现的一个小细节。这个服务本身并不重要,重要的是我在其中一个请求中收到的 HTTP 头部。它包含一个日期,扰乱了我平静专注的精神状态,以至于我不得不写下这篇文章: expires: Thu, 01 Jan 1970 00:00:01 GMT 这里奇怪的不是过期头部,虽然这不是最现代的方式,但可以理解,它的目的不是为了使缓存失效,而是为了避免资源从一开始就被缓存。为了实现这一点,他们将过期日期设置为过去,而最好的日期莫过于全世界几乎没有电子计算机的那个时刻: Thu, 01 Jan 1970 00:00:00 GMT 。 在任何其他服务中,这一秒的差异可能不会引起我的注意,但我们谈论的是 Cloudflare,是 Cloudflare!那些用熔岩灯墙保护互联网的公司,那些缓解了历史上一些最大 DDoS 攻击的公司,那些建造了 1.1.1.1 的公司,那些大规模使用 HTTP/3 的公司,那些甚至敢于保护用户开放互联网权利免受某些人滥用之害的公司。 这一秒的差异之所以存在,是有原因的,答案很可能与仍在运行并支撑着我们文明的软件中处理数据的编码方式有关。 这种日期格式只是一个接口,一种约定,通过它两个或多个部分交换信息,同时隐藏内部实现的细节。这种格式完全可以表示 1970 年之前的日期,甚至公元 0 年之前的日期。 很可能仍然存在许多或多或少古老的软件,它们在内部将 Unix 时间表示为整数,但还赋予了 0 特殊含义。这种实践非常普遍,不仅限于日期,对于任何类型的数据都是如此。...
作者 gerardooscarjt
1332 次阅读
在
hola.cloud ,我们将一个 MongoDB 3.6 迁移到了不同机器之间。为了确保版本不会出问题,我们使用了相同的官方 Docker 镜像。这里分享两个对我们非常有用的脚本。 export.sh #!/bin/bash
# check argument
if [ -z "${1:-}" ]; then echo "Use: $0
" exit 1
fi
BACKUP_DIR="$1"
mkdir -p "$BACKUP_DIR"
docker run --rm --network host \ -v $(pwd)/$BACKUP_DIR:/backup \ mongo:3.6 \ bash -c 'mongodump --host 127.0.0.1 --port 27017 --out /backup' import.sh #!/bin/bash
set -euo pipefail
# check argument
if...
作者 gerardooscarjt
1269 次阅读
#buildinpublic #SeniorGo 从零开始用Golang搭建HTTP服务器 Go语言自带一个健壮、强大且可用于生产的HTTP服务器。而且它非常易于使用,同时又不失灵活性和可配置性,甚至能精确到最微小的细节。 http包包含了一个Server对象,它拥有我们所需的一切。启动它所需的最基本属性是Addr和Handler。 Addr Addr 是服务器将要监听的地址,是一个格式为 :<端口> 的字符串。例如,如果我们想接收网络上任何计算机通过8080端口发来的请求,可以设置为 :8080 或 0.0.0.0:8080 。如果我们在开发时,可以使用 127.0.0.1:8080 ,这样只有本机才能访问(这在Mac上非常有用,可以避免频繁弹出防火墙提示)。 Handler Handler 是一个函数,每当服务器收到HTTP请求时都会被调用。该函数拥有一个 ResponseWriter 用于发送响应,以及一个 Request 用于读取客户端请求。 在接下来的示例中,我们记录HTTP方法和URL的日志,然后返回 "Hello World!!" 作为响应。 package main
import (
"log"
"net/http"
)
func main() {
s := &http.Server{
Addr: ":8080",
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Println(r.Method, r.URL)
w.Write([]byte("Hello World!!"))
}),
}
err := s.ListenAndServe()
if err != nil {
log.Fatal(err)
}
} 如果服务器启动一切顺利,执行将停在 ListenAndServe...
作者 fulldump.net
1441 次阅读
我想为GoPress设计一个易识别的标志,要简洁,能体现博客和双关语的精髓。 我们试试让GPT帮帮忙: “我们需要为一个名为‘gopress’的博客系统打造品牌。它是对WordPress(最大的博客平台)的仿拟。我最初的想法是一个键盘键帽,上面有字母G,既代表按下按键创建文章的动作,也代表印刷媒体中的‘press’。 如果可以,也请为dall-e生成一个提示。” 以下是GPT的回复: 这个初始概念对“GoPress”品牌来说非常棒!基于你的想法,我们可以这样进一步优化和细化: 标志 :一个单独的键盘键帽,上面带有风格化的“G”。这个“G”可以设计成同时微妙地融入笔或打字机的元素,以进一步体现写作的方面。为了代表博客的数字化、现代特性,可以在“G”内部或周围加入电路线或二进制代码设计元素。 配色方案 :将中性科技色(如光滑灰或银色)与鲜艳的亮色相结合。可以包括一种大胆的绿色(代表GoPress中的‘Go’)或一种明亮的蓝色(常与信息和科技关联)。 字体 :“GoPress”这个词可采用现代无衬线字体,清晰易读。可大写首字母“G”和“P”以强调品牌名。 标语 :为了强调信息,可以使用类似“Press to Express”、“Your Thoughts, One Press Away”或“Empowering Voices, One Key at a Time”的标语。 现在,关于DALL-E的提示,你可能想要一个与GoPress品牌形象相符的内容。这是一个建议:“一个键盘键帽,上面有风格化的‘G’,这个‘G’微妙地融入了笔或打字机的元素。‘G’是鲜艳的绿色,周围环绕着电路线或二进制代码设计元素。” 请注意,DALL-E的实际结果可能会有所不同,因为截至我上次训练截止日期2021年9月,DALL-E并未与模型直接集成,且此后模型的能力可能已经进化。 使用它建议的提示,我们在DALL-E中得到的图像很难用于网站图标: 由GPT提示生成的DALL-e图像 再迭代几次后,出现了一些适合用作文章头图的好图像: 提示:“一个来自机械键盘的网站图标键,上面有字母G,亮色” 提示:“一个来自机械键盘的网站图标键,上面有字母G” 似乎没有能用作网站图标的,因为大幅降低分辨率后依然无法识别。 我还在寻找标志,有什么想法吗?
作者 gerardooscarjt
2203 次阅读
Gopress,一个使用Golang的博客(第8部分) 大家好!我们继续关于如何使用Golang(由
Google 创建 且越来越流行的编程语言)构建博客的系列教程。如果你错过了前面的部分,请前往我们之前的文章,并跟上进度。今天,在系列的第八部分中,我们将重点放在身份验证和安全性上。让我们开始吧! 复选框 一 二 三 身份验证与安全性 到目前为止,我们已经创建了具备基本功能的博客Gopress,但尚未实现任何身份验证机制。我们不希望任何人都能在我们的博客上发表、编辑或删除内容。为了防止这种情况,我们需要实现一个身份验证系统。 在Golang中,有多个库可帮助我们进行身份验证,但在本教程中,我们将使用“gorilla/sessions”来处理用户会话,并使用“golang.org/x/crypto/bcrypt”进行密码哈希处理。 使用Gorilla/Sessions实现会话 首先,我们需要 安装 Gorilla Sessions包。如果你使用go modules,可以通过以下命令完成: bashCopy codego get github.com/gorilla/sessions 首先,我们定义一个全局变量来存储会话: goCopy codevar (
key = []byte("super-secret-key")
store = sessions.NewCookieStore(key)
) 完成之后,我们可以实现一个函数,在成功登录后设置会话: goCopy codefunc setSession(userName string, w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, "cookie-name")
session.Values["authenticated"] = true
session.Values["username"] = userName
session.Save(r, w)
} 另一个函数用于检查用户是否已认证:...
作者 gerardooscarjt
2038 次阅读