前一篇 尝试 FastAPI WebSocket 写简单的聊天应用 刚体验了 WebSocket, HTTP 可以共用下层的 TCP 连接保持网页与服务器的双向连接。先简单作个回顾,也是为了解释后面关于 Nginx 反向代理 WebSocket 作准备,比如说下面的 WebSocket 服务ws://localhost:8000/ws
当在浏览器中用 JavaScriptvar ws = new WebSocket("ws://test.exmple.com:8080/ws");
后,浏览器首先会发送一个 GET /ws 的 HTTP 请求,如下(不相关的 HTTP 头省去) Read More
学习完用 Transformers 和 llama.cpp 使用本地大语言模型后,再继续探索如何使用 Ollama 跑模型。Ollama 让运行和管理大语言模型变得更为简单,它构建在 llama.cpp 之上,并有优化,性能表现同样不俗。下面罗列一下它的特点- 从它的 GitHub 项目 ollama/ollama, Go 语言代码 90.8%, C 代码 3.4%
- Ollama 不仅能运行 Llama 模型,还支持 Phi 3, Mistral, Gemma 2 及其他
- Ollama 支持 Linux, Windows, 和 macOS, 安装更简单,不用像 llama.cpp 那样需从源码进行编译,并且直接支持 GPU 的
- Ollama 有自己的模型仓库,无需申请访问权限,可从 Ollama 拉取所需模型,或 push 自己的模型到 Ollama 仓库pull llama3.2-vision
- Ollama 仓库的模型是量化过的,某个模型有大量的 tag 可选择下载,如 llama3.2 的 tags 有 1b, 3b, 3b-instruct-q3_K_M, 1b-instruct-q8_0, 3b-instruct-fp16 等
- 如果在 Ollama 上没有的模型,可以到 HuggingFace 上下载,或量化后再传到 Ollama 仓库
其他更多特性我们将在使用当中体验,仍然是在 i9-13900F + 64G 内存 + RTX 4090 + Ubuntu 22.4 台上进行 Read More
有一个使用了不同数据库的应,Oracle 和 PostgreSQL,数据库中的记录完全相同,相同的查询语句(相同的排序,至少从字面上来说是的)取到的记录排序却不同,从而产生了 Bug。 简单演示一下默认排序各自在这两种数据库中的行为, 比如说表中有两条记录,'VFORX' 和 'ibbVA'。此处不创建物理表。
Oracle(Linux)select * from (
返回的结果是 Read More
select 'VFORX' as value from dual
union
select 'ibbVA' from dual
) order by 1 desc;
使用 Python 的话用不着像 Java 那样是考虑用 Logback 还是 Log4J 的问题,因为它内置提供了完备功能的 logging 库。虽然 JDK 也有 java.util.logging(JUL), 它的特性其实也不差,如日志级别,输出格式,不同的输出目的地的选择,但在 Logback 和 Log4J 的光环之下几乎无人问津。相比而言 Python 的 logging 却极为受宠,非必要时基本不会去考虑引入第三方的日志库,如 Loguru, LogBook, Structlog, Picologging, 尽管它们也很出色,毕竟是庶出。logging 的最基本用法
在基本前面加是最字,是因为这一节仅仅是如何让 logging 作为 print() 的替代品,暂不涉及到参数的传递,异常的输出,以及格式定制,日志往哪里输出的问题。1import logging 2 3logging.info("hello")
运行,什么也看不到,因为 Python logging 的默认级别是 warning, 这不符合人的基本认知,一般 logging.info() 起码是用来替代 print() 的,居然直接用无法输出,不知该库的设计者是怎么个想法。 Read More
回看三年前的一篇日志 Mockito 3.4.0 开始可 Mock 静态方法,最后对 Mockito 产生的缺憾是它无法用来 Mock 非测试线程(主线程)中的静态方法调用。其实这也是可以变通的,下面慢慢道来。
首先回顾一下 Mockito 的静态方法 Mock 的使用方法,随着 Mockito 版本的升级,引入依赖的方式也发生了些许的变化,以 Maven 项目为例,如果在 JUnit 5 下用 Mockito 的 pom.xml 依赖中为1<dependency> 2 <groupId>org.mockito</groupId> 3 <artifactId>mockito-junit-jupiter</artifactId> 4 <version>5.14.1</version> 5 <scope>test</scope> 6</dependency>
由它引入的全部相关依赖
Read More
十来天前写过一篇 Redis 之前如何曲线的方式用作消息队列 使用 Redis 作为消息队列 - Pub/Sub, List, SortedSet. 只能说简单的使用方式勉强还行,离真正意义上的消息队列有些距离。而自 Redis 5.0 加入了 Stream 就更进一步,可望朝着作为正规消息队列的 At most once, At least once, 和 Exactly once 方向迈进。
如果以 Serverless 方式使用 AWS 的 Redis, 那么既然用到高级消息队列的功能,还能省去使用 AmazonMQ(ActiveMQ 或 RabbitMQ) 或 MSK(Kafka) 的高成本。
Redis stream 数据结构像是一个 append-only 日志,但又添加了 O(1) 的随机访问和复杂的消费策略,如消息分组。
Redis Stream 的每条消息会有一个唯一 ID, 支持消费组, Redis 用以支持 Stream 的一系列命令是 X 为前缀的, 完整的 Stream 命令列表。 Read More
PostgreSQL 随着云服务的盛行,越发被广泛的应用,免费开源且有丰富的特性支持,加上性能也很不错,因而备受青睐。PostgreSQL 的函数与存储过程区别并不太大,不像某些数据库的函数与存储过程必须是无副作用或有副作用,在 PostgreSQL 的函数和存储过程中可以进行任何的 SQL 操作。简单列举下 PostgreSQL 的函数与存储过程的区别主要如下:
函数- return 或 out 参数返回值,return 可返回单个值或一系列值(return setof 或 return table), 或返回光标(cursor). 函数 return void 就和存储过程差不多了
- 函数因其有返回值,所以可通过 select, insert, updata 或 delete 语句来调用,如 select fn1(), delete * from test1 where fn2(c1)=0
- 可以用 execute 执行动态 sql, 如 execute 'delete * from ' || 't1'
存储过程- IN, OUT 或 INOUT 参数,但不直接返回值
- 不能用 select, insert 等语句使用
- 不能用 execute 执行动态 sql
接下来我们来体验一下 PostgreSQL 的函数与存储过程 Read More
刚刚回顾了一下 JDBC 操作 SQL Server 时如何传入列表参数,即如何给 in (?) 条件直接传入一个列表参数,然而本质上是不支持,最终不得不展开为 in (?, ?,...?) 针对每个元素单独设置参数,不定长的参数对于重用已编译 PreparedStatement 语句的帮助不大。
那么 JDBC 操作 PostgreSQL 是何种状态呢?展开为多个参数当然是有效的。继续尝试 Spring 提供的 NamedParameterJdbcTemplate 的操作方式
String query = "select * from users where id in (:ids)";
Map<String, Object> parameters = new HashMap<>();
parameters.put("ids", IntStream.rangeClosed(1, 5).boxed().collect(toList()));
List<Map<String, Object>> maps = namedParameterJdbcTemplate.queryForList(query, parameters);执行后查看到实际执行的语句是
select * from users where id in (?, ?, ?, ?, ?)
Read More
Python 是一个动态语言,可以动态的给实例或类增减属性或方法,给类添加的属性会影响到前后所有创建的实例。但是使用__slots__属性可以限定类或实例属性和方法,如果没有__slots__的话实例的属性和方法包含在实例的__dict__字典中,类的属性和方法包含在类的__dict__字典中。
在使用__slots__按常规写法可能会出现的问题大概有- AttributeError: 'Xxx' object has no attribute 'yyy'
- AttributeError: 'Xxx' object attribute 'yyy' is read-only
- ValueError: 'yyy' in __slots__ conflicts with class variable
我们来看下面的例子 Read More
本文旨在测试 Python Flask 框架的默认并发能力,即同时能处理多少个请求,以及请求等待队列大致有多大; 并找到如何改变默认并发数。虽然网上或许很容易找到它们的默认并发数,但通过实验的方式可以得到更感性的认识。
本文写作时使用的环境为- 测试机器为 MacBook Pro, CPU 6 核超线程,内存 16 Gb
- JMeter 5.5 -- 连续发送请或压力测试
- Python 3.10.9
- Flask 2.2.2
从 JMeter 每半秒发送一个请求,连续发送 1000 个,程序中 API 方法接受到请求后 sleep 800 秒,保证在全部 1000 个请求送出之前一直占着连接,以此来找到同时被处理的请求数目,并且有足够的时间统计当前的 TCP 连接数。在测试极端规模的并发数时,由于在 Mac OS X 很难突破 5000 个线程的限制,这时就让 JMeter 分布到远程 Linux(Docker 或虚拟机) 上执行。
请求的 URL 是 http://localhost:8080/?id=${count}, 带一个自增序列用以识别不同的请求, JMeter 的 Thread Group 配置为 Number of Threads (users): 1000, Ramp-up period (seconds): 500 Read More