东风草堂博客

公众号:开发者来风

所谓垃圾回收,即所有的内存分配动作都会被在运行时记录,同时任何对该内存的使用也都会被记录,然后垃圾回收器会对所有已经分配的内存进行跟踪监测,一旦发现有些内存已经不再被任何人使用,就阶段性地回收这些没人用的内存。

1
2
3
4
5
6
// c语言内存回收的考验
int* p = new int;
p += 10; // 对指针进行了偏移,因此那块内存不再被引用
// ...... 这里可能会发生针对这块int内存的垃圾收集 ......
p -= 10; // 咦,居然又偏移到原来的位置
*p = 10; // 如果有垃圾收集,这里就无法保证可以正常运行了

Go语言还内置了一个对于其他静态类型语言通常用库方式支持的字典类型(map)。可以认为数组切片是一种可动态增长的数组,数组切片的功能与C++标准库中的vector非常类似。

1
2
3
4
5
6
7
8
9
10
11
12
// 多返回值
func getName()(firstName, middleName, lastName, nickName string){ return "May", "M", "Chen", "Babe"
}
// 可以返回空值
func getName()(firstName, middleName, lastName, nickName string){ firstName = "May"
middleName = "M"
lastName = "Chen"
nickName = "Babe"
return
// 调用过程
fn, mn, ln, nn := getName()
}

c语言在实现一个接口之前必须先定义该接口,并且将类型和接口紧密绑定,即接口的修改会影响到所有实现了该接口的类型,而Go语言的接口体系则避免了这类问题。

阅读全文 »

分布式锁

在分布式系统中,如何保证多个进程或线程之间对共享资源的访问互斥性和并发性?
在分布式锁的情况下,还是需要单机锁的,可以减少对同时加锁的并发量,减轻中间件的压力。
没有抢到锁怎么处理?自旋,性能差。事件通知回调最好。

如何保证多个进程或线程之间的互斥性和并发性?

在一个分布式系统中,多个进程或线程需要对共享资源进行读写操作,如果不加限制,可能会导致数据不一致或者出现竞态条件。因此,需要引入分布式锁来控制对共享资源的访问。

  1. MySQL实现分布式锁的一种常见方式是使用InnoDB的行级锁和SELECT … FOR UPDATE语句。简单,使用方便,不需要引入Redis、zookeeper等中间件。但不适合高并发的场景,db操作性能较差,没有设置超时时间,有锁表的风险。具体步骤如下:
阅读全文 »

如何确认光猫是桥接还是路由模式?

当数据包进入桥接器时,桥接器会查看源MAC地址,并将其存储在一个表格中。然后,桥接器会检查目的MAC地址,并将其与该表中的所有MAC地址进行比较。如果该目的MAC地址已保存在表格中,桥接器就将数据包切换到与目的MAC地址相应的端口上。如果目的MAC地址不在表格中,则桥接器广播数据包到所有端口。

方法一: 我们用一台电脑的网口使用网线直接连接光猫的LAN口(也就是上网口),若是电脑连上之后能直接上网,那么就说明,光猫为:路由模式。 反之,若是电脑不能直接上网,那么说明光猫是桥接模式,需要电脑拨号,输入上网宽带账号、密码才能拨号上网。
方法二: 我们还可以直接登录光猫的后台管理界面查看,查看网络-网络设置里面的连接模式是路由还是桥接。如下:

常见组网模式

方法一:跑量设备,直接接入光猫LAN口,光猫开启DMZ或者UNPN(推荐);
方法二:光猫连接模式改成桥接、路由器上网模式改成拨号上网。

阅读全文 »

自主部署代理

不用搭环境,自己有境外的vps就行,最好是openai支持的地区的vps,下载bin里面的执行文件直接就能跑,最简单的api proxy方式,最重要的是支持SSE,让客户端请求时响应得更加迅速,也提供了golang的源码,需要定制的可以自行完善。

1
./api_proxy -daemon -port 9000 # 最好开启daemon守护进程模式

docker的部署方式,直接拉镜像部署,不用自己配置环境,这种自主部署的代理可以支持sse,使用nodejs的可以参考:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
sudo yum remove docker
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# https://mirrors.tuna.tsinghua.edu.cn/help/docker-ce/
sed -i 's+https://download.docker.com+https://mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io
sudo systemctl start docker # 这个不要忘了
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
yum install libxcrypt-compat # 报错dlopen: libcrypt.so.1: cannot open shared object file: No such file or directory

# 代理配置,参考https://docs.docker.com/engine/daemon/proxy/#httphttps-proxy,HTTPS_PROXY配成一样的就行
mkdir -p /etc/systemd/system/docker.service.d
touch /etc/systemd/system/docker.service.d/proxy.conf
[Service]
Environment="HTTP_PROXY=http://proxy.example.com:80"
Environment="HTTPS_PROXY=https://proxy.example.com:443"
systemctl daemon-reload
systemctl restart docker

docker pull python:3-slim # 可以用来跑python脚本
docker run -dit --name proxy -p 9000:9000 easychen/ai.level06.com:latest # Proxy地址为 http://${IP}:9000
# 可用环境变量
# PORT: 服务端口
# PROXY_KEY: 代理访问KEY,用于限制访问
# TIMEOUT:请求超时时间,默认5秒

# 新方法
wget https://github.com/Yidadaa/ChatGPT-Next-Web/archive/refs/tags/v1.7.1.tar.gz
tar -xzvf v1.7.1.tar.gz
cd ChatGPT-Next-Web-1.7.1
docker build .
docker tag IMAGEID(镜像id) REPOSITORY:TAG(仓库:标签)
docker login
docker push nephen2023/chatgpt-next-web
阅读全文 »

参考

消息检查是否违规:https://platform.openai.com/docs/guides/moderation/quickstart
怎么开启流式传输:https://platform.openai.com/docs/api-reference/chat/create#chat/create-stream

1
2
stream boolean Optional Defaults to false
Whether to stream back partial progress. If set, tokens will be sent as data-only server-sent events as they become available, with the stream terminated by a data: [DONE] message.

怎么做到连续上下文:https://platform.openai.com/docs/guides/chat/introduction,可以用https://platform.openai.com/playground?mode=chat 进行测试,入下图:刚开始问的时候assistant内容是为空的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 当用户指令引用先前的消息时,包括对话历史记录会有所帮助。
messages=[
# 主要的输入是消息参数。消息必须是一个消息对象的数组,其中每个对象都有一个角色("系统"、"用户 "或 "助手")和内容(消息的内容)。对话可以短到1条消息,也可以写满很多页。
# 通常,对话首先使用系统消息进行格式化,然后是交替的用户和助理消息。
{"role": "system", "content": "You are a helpful assistant."}, # 系统信息有助于设置助手的行为
{"role": "user", "content": "Who won the world series in 2020?"}, # 用户消息有助于指导助手。它们可以由应用程序的最终用户生成,或由开发人员设置为指令
{"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."},
{"role": "user", "content": "Where was it played?"} # 用户消息有助于指导助手。它们可以由应用程序的最终用户生成,或由开发人员设置为指令
]

completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=messages
)

print(completion.choices[0].message)
阅读全文 »

在 Zeabur 上部署

推荐使用 Zeabur,具体操作如下

  1. Fork 这个仓库为你自己的仓库
fork 2. 在 [Zeabur](https://zeabur.com) 部署你的仓库 3. 在 [Zeabur](https://zeabur.com) 控制台新增一个服务 步骤 1
阅读全文 »

考虑到seo,使用nuxtjs建立了自己的产品官网,但是在部署上线后出现了问题,用户说我收藏了某个网页,但是后面请求时都跑到首页去了,我仔细看了一下,刷新网页时确实会先闪现首页,后面再跑到指定的页面。

看了下nginx的请求,是请求的/about,但返回的是首页的页面。

再查了下站点的文件,也没有about文件呀,只有About。

想起来nginx的配置方式,请求不到对应的文件时,会跑到首页去,原因就明确了。

于是我改了文件夹的名字,把大写改为小写,再次请求验证ok。


那nuxtjs为什么会生成大写字母开头的文件夹?看了下源码,是因为vue文件命名成了大写,于是我重新把相关的文件名改为小写,再npm run generate生成静态部署文件就好了。

至于说是坑,可能是自己理解的问题,之前以为是不能使用static静态部署,要使用server模式才行,但是我这种小网站不想这么折腾,网上有人说用server模式加nginx反向代理就好了,其实不是这个问题,所以写篇文章记录一下。
贴一下相关的配置。

1
2
3
4
5
6
7
8
9
10
11
// nuxt.config.js
// npm run generate,再部署dist文件夹
ssr: true,
target: 'static',
// nginx.conf
index index.html index.htm index.nginx-debian.html;
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ /index.html;
}

定制小程序和星级用户有什么关系?

  1. 定制小程序和星级用户都拥有小程序的最高级别权限,都可以长期使用。
  2. 定制小程序的主体是你自己,因为这个小程序是你自己申请注册的,等于这个小程序就是属于你自己的了,所以小程序的名字可以自己命名。
  3. 定制小程序后,这个小程序就只有你自己一个人使用,留言内容可以由你自己把控,而星级用户使用的公共的小程序,有很多公众号使用,存在评论管理相关的风险。

定制开发流程

  1. 微信公众平台注册一个小程序,激活后使用注册好的邮箱/密码登录进入小程序后台。
  2. 补充小程序的基本信息,如名称、图标、描述等。名称、图标、描述先和自己的公众号名字保持一致。
  3. 加客服进入后续的开发工作。
  4. 开发完成,提交微信审核。
  5. 审核通过,上线即可使用。
  6. 客服联系你,教你怎么使用留言板小程序。

定制开发价格

阅读全文 »

守护进程简介

守护进程(deamon)是生存期长的一种进程。它们常常在系统引导装入时启动(如果需要守护进程随系统自启动,需要在/etc/init.d目录下放置响应的启动脚本,或者利用systemctl来控制,还有一些其他方法如supervisor等,读者可自行网上搜索相关用法),仅在系统关闭时才终止。因为它们没有控制终端,所以说它们是在后台运行的。

从daemon的启动和管理方式区分,可以将daemon分为两大类:可独立启动的daemon(stand alone)和由一个超级daemon(super daemon)来统一管理的daemon。

  • stand alone:可单独自行启动的daemon。这种daemon启动后会一直占用内存和系统资源,最大的优点是响应速度快,多用于能够随时接受远程请求的服务,如WWW的daemon(httpd)、FTP的daemon(vsftpd)等。
  • super daemon:由一个特殊的daemon来统一管理。这种服务通过一个统一的daemon在需要时负责唤醒,当没有远程请求时,这些服务都是未启动的,等到有远程请求过来时,super daemon才唤醒相应的服务。当远程请求结束后,被唤醒的服务会关闭并释放系统资源。早期的super daemon是inetd,后来被xinetd替代了。super daemon本身是一个stand alone的服务,因为它需要管理后续的其他服务,所以它自己本身当然需要常驻内存中。

守护进程创建步骤

阅读全文 »

Windows Subsystem for Linux(简称WSL)是一个在Windows 10上能够运行原生Linux二进制可执行文件(ELF格式)的兼容层。它是由微软与Canonical公司合作开发,其目标是使纯正的Ubuntu、Debian等映像能下载和解压到用户的本地计算机,并且映像内的工具和实用工具能在此子系统上原生运行。

使用了wsl可以丢弃VMware。

安装wsl

参考:https://docs.microsoft.com/en-us/windows/wsl/install-manual

PowerShell执行下面命令安装wsl:

阅读全文 »
0%