MySQL 8:授权用户远程访问语句
ALTER USER 'root'@'%' IDENTIFIED BY 'pwd' PASSWORD EXPIRE NEVER;
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'pwd';
FLUSH PRIVILEGES;
ALTER USER 'root'@'%' IDENTIFIED BY 'pwd' PASSWORD EXPIRE NEVER;
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'pwd';
FLUSH PRIVILEGES;
pve 8.2
1、第一步,升级pve内核到最新
1)设置dns,让源域名可以解析
2)设置国内源
#编辑 Debian sources.list 源文件,写入国内源
nano /etc/apt/sources.list
# 内容如下:
deb https://mirrors.ustc.edu.cn/debian/ bookworm main contrib
deb-src https://mirrors.ustc.edu.cn/debian/ bookworm main contribe
deb https://mirrors.ustc.edu.cn/debian/ bookworm-updates main contrib
deb-src https://mirrors.ustc.edu.cn/debian/ bookworm-updates main contrib
# 编辑 PVE 源文件 pve-no-subscription.list
nano /etc/apt/sources.list.d/pve-no-subscription.list
# 内容如下:
deb https://mirrors.tuna.tsinghua.edu.cn/proxmox/debian bookworm pve-no-subscription
# 编辑屏蔽 PVE 企业源文件
nano /etc/apt/sources.list.d/pve-enterprise.list
# 将下面这一行注释掉 (前面加上井号)
# deb https://mirrors.tuna.tsinghua.edu.cn/proxmox/debian bookworm pve-no-subscription
3)升级内核
数据中心 – pve 节点 – 更新 – 升级
升级结束重启
2、第二步,虚拟机先安装系统
正常的虚拟机配置(默认配置),安装好飞牛OS系统。
BIOS选择 OVMF(UEFI)
BIOS 关闭 Secure Boot
处理器类型选择 host
显卡 默认
机型 默认
3、第三步,设置显卡直通
1)虚拟机停机,如果pve控制台停机不了,则网页进入飞牛系统关机。
pve节点配置参数
nano /etc/pve/qemu-server/101.conf
args%3A -set device.hostpci0.addr=02.0
飞牛os虚拟机设置:
2)显卡 选择 无
3)机型 选择 q35
5)添加PCI设备,选择原始设备 0000:00:02.0,勾选所有功能,主GPU、PCI-Express 不要勾选。
6)启动虚拟机,飞牛OS设置中查看是否显示GPU,影视播放启用硬解,并播放其他分辨率查看GPU占用情况。
ps:不同主机的GPU编号可能不同,比如 0000:00:02.0 ,device.hostpci0.addr=02.0
第一步:创建容器
docker create --name=tinymediamanager \
-e GROUP_ID=0 -e USER_ID=0 -e TZ=Asia/Shanghai \
-p 5800:5800 \
-p 5900:5900 \
dzhuang/tinymediamanager:latest-v5
PS: 网络已通过 https://wizzer.cn/archives/3804 配好,可以自动 pull 镜像文件
第二步:磁盘映射
NAS路径 -> 映射路径
/docker/ttm/config -> /config
/video -> /video
http://10.10.10.10:5800 访问,即可查看界面。
BUDIOT 是一个开源的、企业级的物联网平台,它集成了设备管理、协议解析、消息订阅、场景联动等一系列物联网核心能力,支持以平台适配设备的方式连接海量设备,支持在线下发指令实现远程控制,支持扩展水电气等各类计费业务场景。
本平台是在千万级设备实时计费物联网平台经验基础上,在不损失性能的前提下进行功能删减、结构优化而来,小而美,同时又具备灵活的扩展性。
在线演示地址: https://demo.budiot.com 用户名: superadmin 密码: 1
基于自研 Java 微服务框架 https://budwk.com
budiot-access/budiot-access-gateway
设备网关,用于设备协议和 network 组件budiot-access/budiot-access-processor
设备数据上报业务处理模块budiot-server
WEB 服务 API ,定时任务等budiot-access/budiot-access-network
网络组件,支持 TCP/MQTT/UDP/HTTP 等budiot-access/budiot-access-protocol
设备协议开发包,内含 demo 示例budiot-access/budiot-access-storage
设备数据存储,可扩展时序数据库等budiot-vue-admin
Vue3 + Element-Plus默认采用 MongoDB 7 的时序集合,可根据项目规模需要,扩展为 TDEngine 等时序数据库
原文地址:https://blog.chai.ac.cn/posts/docker-proxy
最后更新:2024年7月15日
最近又见识到了一些神奇的骚操作,考虑到在将来 Docker 的国内各个镜像站可能变得不可用,需要未雨绸缪一下。 有旁路由自然是好的,但现在打算用 Proxy 来解决这个问题。 由于群晖的 Container Manager 是基于 Docker 的,但部分配置路径不同,所以特意记录一下。
注意事项:
192.168.50.100:7893
群晖 Container Manager 用户可以跳过这一小节,你实际上已经有 Docker 了。
Docker Engine 安装过程请参考 官方文档。
Docker 官方给出了许多安装方式,我选择用 apt
从官方维护的源中安装。
你也可以选择手动下载二进制包,然后用 dpkg
安装.
这里选择使用 apt
演示,关键在于很多人还不清楚如何为 apt
设置代理:
shell
sudo vi /etc/apt/apt.conf
shell
Acquire::http::Proxy "http://192.168.50.100:7893";
Acquire::https::Proxy "http://192.168.50.100:7893";
注意第二个行依旧是 http
协议,否则会碰到 TLS Could not handshake 问题。 代理服务器只需要负责做请求转发和响应转发,不会像 HTTPS 协议一样进行解密和加密。
安装完成后,官网教程会让你运行 docker run hello-world
来验证安装是否成功。
默认情况下,你的本地肯定不存在任何有关镜像(如下所示),因此会从官方库拉取:
shell
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1ec31eb5944: Retrying in 1 second
docker: error pulling image configuration:
download failed after attempts=6: dial tcp 31.13.82.33:443: i/o timeout.
执行拉取操作的是 Docker Daemon,参考 官方文档 进行 Proxy 有关的设置:
提示
使用 docker info
可以查询到版本信息,版本太低的话请参考下一节的方法。
Docker Daemon 大多数配置选项都可根据 daemon.json
文件进行设置。
对于 Docker 引擎 23.0 及更高版本,可以在该文件中设置代理行为:
/etc/docker/daemon.json
~/.config/docker/daemon.json
/var/packages/ContainerManager/etc/docker.json
shell
{
"proxies": {
"http-proxy": "http://192.168.50.100:7893",
"https-proxy": "http://192.168.50.100:7893",
"no-proxy": "127.0.0.0/8"
}
}
这些配置将覆盖 docker.service
默认的 systemd 设定。
如果您位于 HTTP 或 HTTPS 代理服务器后面,例如在公司设置中, 则必须在 systemd 服务文件中指定守护程序代理配置,而不是在 daemon.json
文件中或使用环境变量。
如 Docker 版本太低,不支持通过 daemon.json
配置代理,则需手动创建 systemd 文件:
/etc/systemd/system/docker.service.d
~/.config/systemd/user/docker.service.d
/etc/systemd/system/pkg-ContainerManager-dockerd.service.d
添加 http-proxy.conf
文件,下面以群晖 Container Manager 为例:
shell
sudo mkdir -p /etc/systemd/system/pkg-ContainerManager-dockerd.service.d
sudo vi /etc/systemd/system/pkg-ContainerManager-dockerd.service.d/http-proxy.conf
shell
[Service]
Environment="HTTP_PROXY=http://192.168.50.100:7893"
Environment="HTTPS_PROXY=http://192.168.50.100:7893"
Environment="NO_PROXY=localhost,127.0.0.1"
如果你有内建的 registry-mirrors
, 记得加入 NO_PROXY
中。
不论采用上面哪种方式,都需要重启 Docker Daemon 服务:
synoservice
代替 systemctl
.systemctl --user
代替 sudo systemctl
.下面仅仅给出 root 模式和群晖 Container Manager 的重启方法:
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl restart pkg-ContainerManager-dockerd.service
重启 Docker/Conatiner Manager 服务需要一定的时间,取决于你正在运行的容器数量。
检查设置是否生效:
sudo systemctl show --property=Environment docker
systemctl show --property=Environment pkg-ContainerManager-dockerd.service
再次跑 docker run hello-world
,应该就能成功了。
有的时候,你使用的 Docker 镜像在 build
和 run
时也需要代理。 大部分应该都知道怎么配置,或者会通过环境变量来设置。 但有的时候希望代理配置默认对所有容器生效(那为什么不用机器或路由级别的代理呢),可以参考下面的方法。
参考 官方文档 中的说明,你可以在 ~/.docker/config.json
中设置代理。
shell
{
"proxies": {
"default": {
"httpProxy": "http://192.168.50.100:7893",
"httpsProxy": "http://192.168.50.100:7893",
"noProxy": "127.0.0.0/8"
}
}
}
保存文件后配置将生效,适用于新容器的生成和运行,无需重启 Docker,
本质上,它通过影响 Docker CLI 来添加环境变量,效果类似于:
shell
docker build --build-arg HTTP_PROXY="http://192.168.50.100:7893" .
docker run --env HTTP_PROXY="http://192.168.50.100:7893" redis
但一般还是建议单独针对需要代理服务的容器手动设置这些环境变量, 同样地,一些 Docker 内的应用是不按照环境变量来设置代理的,需要手动配置,需要额外注意。 折腾了这么多,是不是还是觉得旁路由+规则代理的方法会更加简单呢?这就看个人需求了。
java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: Comparison method violates its general contract!
错误代码: children.sort((o1, o2) -> (int) (o2.getLong("createdAt", 0) - o1.getLong("createdAt", 0)));
修复后: children.sort((o1, o2) -> Long.compare(o2.getLong("createdAt", 0), o1.getLong("createdAt", 0)));
排序器 children.sort((o1, o2) -> (int) (o2.getLong("createdAt", 0) - o1.getLong("createdAt", 0)));
存在一个潜在的问题,即当时间戳的差值超出 int
的范围时,强制转换为 int
会导致数据溢出,从而导致比较结果不正确。
一个解决方法是使用 Long.compare
方法进行比较,而不是手动进行减法运算。Long.compare
方法确保了比较的对称性和一致性。
Mongod 的服务模型是每个网络连接由一个单独的线程来处理,每个线程配置了1MB 的栈空间,当网络连接数太多时,过多的线程会导致上下文切换开销变大,同时内存开销也会上涨。
&maxPoolSize=xx
在ConnectionURI上追加上去即可,否则默认每个客户端就是高处100来个,平白的浪费资源启动需指定配置文件(配置数据库用户和密码,用户不可为默认用户)
python3 odoo-bin -c debian/odoo.conf -i base -d odoo
配置文件
[options]
; This is the password that allows database operations:
; admin_passwd = admin
db_host = 127.0.0.1
db_port = 5432
db_user = odoo
db_password = 1234567890
addons_path = /data/odoo/addons
default_productivity_apps = True
需安装依赖
pip3 install -r requirements.txt
su postgres
pgsql
\l 列出数据库
\du 列出用户
\q 退出窗口
su – postgres
pgsql
select usename,passwd from pg_shadow;
ALTER USER demo with password ‘demo12345678’;
或创建用户
CREATE USER demo WITH PASSWORD ‘demo12345678’;
赋予权限
ALTER USER demo WITH SUPERUSER;
ALTER USER demo WITH CreateDB;
创建数据库
CREATE DATABASEdemo
OWNERdemo
;
1、文档说明要求 python 3版本,但没有说必须是 3.6 版本,其他版本报错找不到 libpython3.6m.so.1.0;
2、使用 python 3.6 得安装 requests 组件,文档没有说明;
3、部署时必须指定执行的 sh 脚本文件;
Dcokerfile 文件内容如下:
FROM python:3.6-slim
WROKDIR /app
COPY . /app
RUN python -m pip install --upgrade pip
RUN pip install requests
RUN pip install pycryptodome
EXPOSE 8080
ps:搞过微信开发的都知道,微信的开发文档到底是多么多么的……
职位描述:
1、负责与开发组长沟通业务需求,与后端开发人员对接后端API、开发前端页面;
2、负责修改公司现有软件项目BUG,并对前端功能的持续优化改进;
3、负责公司现有前端框架和组件的维护、改进;
职位要求:
1、2年以上前端开发经验;
2、熟悉Web前端开发基础技能(HTML/CSS/JavaScript);
3、熟悉Vue2、Vue3、ElementUI、Element-Plus等前端开发框架;
4、对前端工程化与模块化开发有一定了解,有webpack/vite/npm实践经验;
5、有GIS开发经验(电子围栏、轨迹、图层等)、数据大屏开发经验者优先;
6、对前端开发有浓厚兴趣,能主动学习;
7、有良好的编码习惯,重视代码质量;
8、善于沟通,工作积极,有责任心,善于协作与分享;
岗位职责:
1、负责Java软件项目的全流程测试,包括制定测试计划、编写测试方案和测试用例等;
2、负责Java软件项目的功能、性能等方面的测试工作,执行测试用例,提交BUG,并进行BUG跟踪和回归测试,直到BUG解决;
3、负责Java软件项目的日常更新维护,包括Docker容器化部署等环境;
4、负责收集、跟进客户的使用问题,直到问题被有效解决;
任职资格:
1、本科及以上学历,计算机或相关专业,3年以上软件测试经验;
2、熟悉软件研发、测试流程,了解过程标准和规范,能主动在关键过程节点推动任务执行;
3、熟悉软件测试方法和软件工程知识,流程意识强,具备有效发现问题和解决问题的能力;
4、熟悉Docker部署,熟练掌握Linux服务器的配置和管理;
5、了解常见开源软件的集群化部署、维护和使用,例如RabbitMQ,MongoDB,Redis,MySQL/MariaDB、ElasticSearch等
6、具有一定的文档编写能力,如部署文档、测试方案、测试用例等;
<style scoped>
::v-deep .el-table {
display: flex;
flex-direction: column;
}
::v-deep .el-table__body-wrapper {
order: 1;
}
::v-deep .el-table__fixed-body-wrapper {
top: 92px !important;
}
::v-deep .el-table__fixed-footer-wrapper {
z-index: 0;
top: 45px;
}
</style>
<template>
<div class="data-list">
<transition name="el-fade-in">
<div v-show="selectRows.length > 0" class="el-selection-bar">
选择了<span class="el-selection-bar__text">{{ selectRows.length }}</span
>条数据
<a class="el-selection-bar__clear" @click="clearSelection">清空</a>
</div>
</transition>
<div v-loading="isRequestIng" class="data-list__table" :element-loading-text="loadingTxt">
<span v-if="summary">总条数:{{ rows.length }}</span>
<el-table
v-bind="$attrs"
ref="tabList"
:data="rows"
v-on="$listeners"
:border="true"
:span-method="handleRowSpanMethod"
:show-summary="summary"
sum-text=" 汇 总 "
>
<slot />
<pro-empty slot="empty" />
</el-table>
</div>
<div v-if="!summary && (pageData.totalCount > pageData.pageSize || pageData.pageSize > 10)" class="data-list__pager">
<el-pagination
:current-page="pageData.pageNo"
:page-size="pageData.pageSize"
:total="pageData.totalCount"
background
:page-sizes="pageSizes"
layout="total, ->, prev, pager, next, sizes, jumper"
@current-change="doChangePage"
@size-change="doSizeChange"
/>
</div>
</div>
</template>
<script>
import { forIn, findIndex, cloneDeep, remove, uniqBy, concat, isArray, first } from "lodash-es"
import { f } from 'vue-marquee-component'
export default {
name: "PlusTableList",
props: {
server: {
type: String,
require: true,
default: ""
},
methods: {
type: String,
default: "post"
},
lazy: {
type: Boolean,
default: false
},
data: {
type: Object,
default: () => {}
},
dataFilter: {
type: Function,
default: data => data
},
loadingTxt: {
type: String,
default: "数据加载中..."
},
paramClear: {
type: Boolean,
default: false
},
selectRows: {
type: Array,
default: () => []
},
selectable: {
type: Function,
default: () => true
},
rowKey: {
type: String,
default: "id"
},
selection: {
type: Boolean,
default: true
},
pageSizes: {
type: Array,
default: () => [10, 20, 30, 50]
},
// 合并行(第一列)
spanName0: {
type: String,
default: null
},
// 合并行(第二列)
spanName1: {
type: String,
default: null
},
// 是否汇总数据
summary: {
type: Boolean,
default: false
}
},
data() {
return {
pageData: {
pageNo: 1,
pageSize: 10,
totalCount: 0
},
rows: [],
isRequestIng: false
}
},
watch: {
pageSizes: {
handler: function (val) {
if (isArray(val)) {
this.pageData.pageSize = first(val)
}
},
immediate: true
}
},
mounted() {
if (!this.lazy) {
this.getList()
}
},
methods: {
// 合并相同值的行
handleRowSpanMethod({ row, column, rowIndex, columnIndex }) {
if (columnIndex === 0) {
if (!this.spanName0) return
if (rowIndex > 0 && row[this.spanName0] === this.rows[rowIndex - 1][this.spanName0]) {
return {
rowspan: 0,
colspan: 0
}
} else {
let count = 1
for (let i = rowIndex + 1; i < this.rows.length; i++) {
if (row[this.spanName0] === this.rows[i][this.spanName0]) {
count++
} else {
break
}
}
if(count>1){
return {
rowspan: count,
colspan: 1
}
}
}
}
if (columnIndex === 1) {
if (!this.spanName1) return
// 第一列值相同,且第二列值相同的的情况下合并
if (rowIndex > 0 && row[this.spanName0] === this.rows[rowIndex-1][this.spanName0] && row[this.spanName1] === this.rows[rowIndex - 1][this.spanName1]) {
return {
rowspan: 0,
colspan: 0
}
} else {
let count = 1
for (let i = rowIndex + 1; i < this.rows.length; i++) {
// 第一列值相同,且第二列值相同的的情况下合并
if (row[this.spanName0] === this.rows[i][this.spanName0] && row[this.spanName1] === this.rows[i][this.spanName1]) {
count++
} else {
break
}
}
if(count>1){
return {
rowspan: count,
colspan: 1
}
}
}
}
},
// 页码变动事件
doChangePage(val) {
this.pageData.pageNo = val
this.getList()
},
// 页大小变动事件
doSizeChange(val) {
this.pageData.pageSize = val
this.pageData.pageNo = 1
this.getList()
},
getList() {
const { totalCount, ...pager } = this.pageData
const params = Object.assign({}, this.data, pager)
if (this.paramClear) {
forIn(params, (value, key) => {
if (value === "") delete params[key]
})
}
this.isRequestIng = true
this.$get(params)
.then(({ data }) => {
this.rows = this.dataFilter(data.list || [])
this.pageData.totalCount = data.totalCount
this.$emit("updateTotal", data.totalCount)
this.isRequestIng = false
this.$nextTick(() => {
this.handlePageUpdate()
})
})
.catch(error => {
this.isRequestIng = false
})
},
handlePageUpdate() {
const list = this.rows
list.forEach(row => {
if (
findIndex(this.selectRows, el => {
return el[this.rowKey] === row[this.rowKey]
}) !== -1
) {
this.$refs.tabList.toggleRowSelection(row, true)
}
})
},
handleSelectionChange(val) {
const selectRows = cloneDeep(this.selectRows)
this.$nextTick(() => {
const list = this.rows.map(el => el[this.rowKey])
remove(selectRows, el => {
return list.includes(el[this.rowKey])
})
this.$emit(
"update:selectRows",
uniqBy(concat(selectRows, val), el => el[this.rowKey])
)
})
},
$get(data) {
if (this.methods === "get") {
return this.$axios.get(this.server, {
params: data
})
} else {
return this.$axios.post(this.server, data)
}
},
reset() {
this.pageData.pageNo = 1
this.pageData.totalCount = 0
this.rows = []
this.clearSelection()
},
async clearSelection() {
this.$refs.tabList.clearSelection()
await this.$nextTick()
this.$emit("update:selectRows", [])
},
query() {
this.reset()
this.getList()
}
}
}
</script>
<template>
<div class="data-list">
<transition name="el-fade-in">
<div v-show="selectRows.length > 0" class="el-selection-bar">
选择了<span class="el-selection-bar__text">{{ selectRows.length }}</span
>条数据
<a class="el-selection-bar__clear" @click="clearSelection">清空</a>
</div>
</transition>
<div v-loading="isRequestIng" class="data-list__table" :element-loading-text="loadingTxt">
<el-table
v-bind="$attrs"
ref="tabList"
:data="rows"
v-on="$listeners"
:border="true"
:span-method="handleRowSpanMethod"
>
<slot />
<pro-empty slot="empty" />
</el-table>
</div>
<div v-if="pageData.totalCount > pageData.pageSize || pageData.pageSize > 10" class="data-list__pager">
<el-pagination
:current-page="pageData.pageNo"
:page-size="pageData.pageSize"
:total="pageData.totalCount"
background
:page-sizes="pageSizes"
layout="total, ->, prev, pager, next, sizes, jumper"
@current-change="doChangePage"
@size-change="doSizeChange"
/>
</div>
</div>
</template>
<script>
import { forIn, findIndex, cloneDeep, remove, uniqBy, concat, isArray, first } from "lodash-es"
export default {
name: "PlusTableList",
props: {
server: {
type: String,
require: true,
default: ""
},
methods: {
type: String,
default: "post"
},
lazy: {
type: Boolean,
default: false
},
data: {
type: Object,
default: () => {}
},
dataFilter: {
type: Function,
default: data => data
},
loadingTxt: {
type: String,
default: "数据加载中..."
},
paramClear: {
type: Boolean,
default: false
},
selectRows: {
type: Array,
default: () => []
},
selectable: {
type: Function,
default: () => true
},
rowKey: {
type: String,
default: "id"
},
selection: {
type: Boolean,
default: true
},
pageSizes: {
type: Array,
default: () => [10, 20, 30, 50]
},
spanName0: {
type: String,
default: null
},
spanName1: {
type: String,
default: null
}
},
data() {
return {
pageData: {
pageNo: 1,
pageSize: 10,
totalCount: 0
},
rows: [],
isRequestIng: false
}
},
watch: {
pageSizes: {
handler: function (val) {
if (isArray(val)) {
this.pageData.pageSize = first(val)
}
},
immediate: true
}
},
mounted() {
if (!this.lazy) {
this.getList()
}
},
methods: {
// 合并相同值的行
handleRowSpanMethod({ row, column, rowIndex, columnIndex }) {
if (columnIndex === 0) {
if (!this.spanName0) return
if (rowIndex > 0 && row[this.spanName0] === this.rows[rowIndex - 1][this.spanName0]) {
return {
rowspan: 0,
colspan: 0
}
} else {
let count = 1
for (let i = rowIndex + 1; i < this.rows.length; i++) {
if (row[this.spanName0] === this.rows[i][this.spanName0]) {
count++
} else {
break
}
}
if(count>1){
return {
rowspan: count,
colspan: 1
}
}
}
}
if (columnIndex === 1) {
if (!this.spanName1) return
// 第一列值相同,且第二列值相同的的情况下合并
if (rowIndex > 0 && row[this.spanName0] === this.rows[rowIndex-1][this.spanName0] && row[this.spanName1] === this.rows[rowIndex - 1][this.spanName1]) {
return {
rowspan: 0,
colspan: 0
}
} else {
let count = 1
for (let i = rowIndex + 1; i < this.rows.length; i++) {
// 第一列值相同,且第二列值相同的的情况下合并
if (row[this.spanName0] === this.rows[i][this.spanName0] && row[this.spanName1] === this.rows[i][this.spanName1]) {
count++
} else {
break
}
}
if(count>1){
return {
rowspan: count,
colspan: 1
}
}
}
}
},
// 页码变动事件
doChangePage(val) {
this.pageData.pageNo = val
this.getList()
},
// 页大小变动事件
doSizeChange(val) {
this.pageData.pageSize = val
this.pageData.pageNo = 1
this.getList()
},
getList() {
const { totalCount, ...pager } = this.pageData
const params = Object.assign({}, this.data, pager)
if (this.paramClear) {
forIn(params, (value, key) => {
if (value === "") delete params[key]
})
}
this.isRequestIng = true
this.$get(params)
.then(({ data }) => {
this.rows = this.dataFilter(data.list || [])
this.pageData.totalCount = data.totalCount
this.$emit("updateTotal", data.totalCount)
this.isRequestIng = false
this.$nextTick(() => {
this.handlePageUpdate()
})
})
.catch(error => {
this.isRequestIng = false
})
},
handlePageUpdate() {
const list = this.rows
list.forEach(row => {
if (
findIndex(this.selectRows, el => {
return el[this.rowKey] === row[this.rowKey]
}) !== -1
) {
this.$refs.tabList.toggleRowSelection(row, true)
}
})
},
handleSelectionChange(val) {
const selectRows = cloneDeep(this.selectRows)
this.$nextTick(() => {
const list = this.rows.map(el => el[this.rowKey])
remove(selectRows, el => {
return list.includes(el[this.rowKey])
})
this.$emit(
"update:selectRows",
uniqBy(concat(selectRows, val), el => el[this.rowKey])
)
})
},
$get(data) {
if (this.methods === "get") {
return this.$axios.get(this.server, {
params: data
})
} else {
return this.$axios.post(this.server, data)
}
},
reset() {
this.pageData.pageNo = 1
this.pageData.totalCount = 0
this.rows = []
this.clearSelection()
},
async clearSelection() {
this.$refs.tabList.clearSelection()
await this.$nextTick()
this.$emit("update:selectRows", [])
},
query() {
this.reset()
this.getList()
}
}
}
</script>
@IocBean
@Slf4j
public class CimApiServer {
@Inject
private RedisService redisService;
private String redis_key = "cim:accessToken";
@Inject
@Reference(check = false)
private ISysConfigProvider sysConfigProvider;
public String getAccessToken() {
String token = redisService.get(redis_key);
if (Strings.isBlank(token)) {
token = this.getHttpToken();
redisService.setex(redis_key, 3600 * 24 - 100, token);
}
return token;
}
private String getHttpToken() {
String CIM_GIS_APPID = sysConfigProvider.getString("COMMON", "CIM_GIS_APPID");
String CIM_GIS_HTTP_BASE = sysConfigProvider.getString("COMMON", "CIM_GIS_HTTP_BASE");
String CIM_GIS_APPKEY = sysConfigProvider.getString("COMMON", "CIM_GIS_APPKEY");
String CIM_GIS_APPSECRET = sysConfigProvider.getString("COMMON", "CIM_GIS_APPSECRET");
Map<String, Object> params = new HashMap<>();
params.put("apiKey", CIM_GIS_APPKEY);
params.put("secret", CIM_GIS_APPSECRET);
Header header = Header.create();
header.addv("Content-Type", "application/json");
Request request = Request.create(CIM_GIS_HTTP_BASE + "/auth/getAccessToken", Request.METHOD.POST);
request.setHeader(header);
request.setData(Json.toJson(params));
Sender sender = Sender.create(request).setTimeout(20 * 1000);
if (CIM_GIS_HTTP_BASE.startsWith("https")) {
try {
SSLContext sslcontext = createIgnoreVerifySSL();
sender.setSSLSocketFactory(sslcontext.getSocketFactory());
sender.setHostnameVerifier((urlHostName, session) -> true);
} catch (Exception e) {
e.printStackTrace();
}
}
Response response = sender.send();
if (response.isOK()) {
NutMap map = Json.fromJson(NutMap.class, response.getContent());
log.debug("getHttpToken:::" + Json.toJson(map));
if (0 == map.getInt("code")) {
return map.getString("data");
}
}
return "";
}
private static class TrustAllManager
implements X509TrustManager {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkServerTrusted(X509Certificate[] certs,
String authType) {
}
public void checkClientTrusted(X509Certificate[] certs,
String authType) {
}
}
public SSLContext createIgnoreVerifySSL() throws NoSuchAlgorithmException, KeyManagementException {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new TrustAllManager()}, null);
return sc;
}
}
阿布大树
喜欢写科普的游戏制作人
【本文已经连续加更8次,阅读字数32000+,阅读时长1个半小时,请大家合理安排阅读时间】
杨振宁是一位理论物理学家,而理论物理学家是最有可能怀疑这个世界的本质其实是有人创造出来的一个虚拟世界。
为什么呢?
我们先假设一下,这个世界真的是个“黑客帝国”式的虚拟世界,那么我们怎么发现这个真相呢?
从哲学角度来讲,只要世界虚拟的足够真实,我们是不可能发现这一点的,我们无法区分“真正的客观”和“完美满足意识主观观察的虚拟客观”之间有任何的区别。
那么,我们这个世界足够真实吗?
在物理学发展到量子阶段以前,我们认为是足够真实的,一切我们发现的科学规律都是既普适又自洽,而且经过思考以后会发现也非常符合直觉和逻辑。包括经典力学,热力学,电磁理论等等,完全看不出有任何的问题,学起来也很容易。
可是,自从物理学发展到量子阶段后,各种反直觉的实验现象就开始出现了。
首先是光的波粒二象性,一个物体,既是波又是粒子,而且到底是波还是粒子居然取决于你怎样观测。这已经很反常识了,幸好科学不屈从于直觉,科学家们想不明白就不想了,姑且认为猫就是可以又死又活吧。
然后半透镜实验(延迟选择实验)就更离谱了,科学家摆弄来摆弄去,就是发现现实世界不遵守因果律。为什么会这样不符合逻辑?没有任何人知道。幸好科学不屈从于逻辑,实验结果如此就如此吧,科学家们只相信事实。
接着又是光子的全同性问题,两个光子,或者很多基本粒子,居然是不能编号区分的,它们可以任意混淆,而且一旦产生混淆,用来区分它们的现象也就随之消失了。这又是违背直觉和逻辑的现象,我们从出生就知道两件东西长的再怎样相似,也是可以彼此区分的,为什么粒子就不可以?物理学家也不知道,只能认同事实。
再接着是更加诡异的粒子的自旋现象,粒子的自旋就像是一种奇怪的秉性,你测量一次,它就有可能变化一次,明明刚用磁场区分出来一致方向自旋的粒子,再次区分,它们依然还是一半向上一半向下,这符合常识吗?当然不,而物理学家们只好用一句自旋现象没有经典对应来一语带过。
然后还有量子纠缠问题,超越光速的超距作用,仿佛空间是不真实存在的,为什么会这样?物理学家还是不知道,哪怕他们可以用公式描述,甚至可以用这个规律来进行保密通讯,但是没有人能给出一个符合直觉和逻辑的简洁解答。
当然,你可以说物理学有了很多解释,什么哥本哈根理论,多世界理论,可是没有一个听起来感觉是能令人信服的,世界在不断分裂成平行世界?时光会回溯?全世界就一个电子?你还不如让我去多看几本科幻。
现代的物理学家们只能承认,量子现象是无法用直觉来理解的,无论你能如何了解这些规律,但是从内心里,你并不是真正能明白了然为什么会这样。甚至很多研究了一辈子量子物理的大神们,这样的疑问也同样盘旋在他们的心里。
这像不像一个不够完美的世界?科学家们会不会在内心中生出一丝疑惑来:这些现象太类似一个人为创造出来的虚拟世界了。
对啊,虚拟世界里物质就可以同时是波函数也可以是确定的值,比如一个随机函数,没有运行的时候就是一个随机范围,运行后(观测)就是一个确定的值。网络游戏里这个现象太普遍了,一张地图上如果有50%的概率刷出怪来,但是没有玩家进入地图前,刷怪程序并不执行,那么如果没有玩家去看,请问地图上有怪吗?
可能有,也可能没有,各50%的概率,处于一种叠加态吧。
但是只要有玩家进入地图,这个叠加态迅速就坍缩了,得到了一个确定的结果。
粒子的全同性在真实世界很难理解对吧,在虚拟世界里多么好理解啊。游戏里面掉落的钱币,因为数量太多,为了方便携带,玩家拾取后就会落到一个背包格子里,这时候它和原来格子里面的钱币就不能区分了,因为这种大数量道具系统是不区分的,还有血瓶,材料等等。全世界就一个钱币?确实是,就一个钱币的代码,到处生成对象而已,同一个代码生成的无编号对象当然就是全同的嘛,你拿哪些全同量子的实验来试试,全部完美解释。
如果我们知道了粒子只是用函数模拟出来的,那么粒子的那些奇怪的内禀属性就不再神奇了。比如电子的自旋属性,要不是我们非要把电子想象成一个小球的话,哪里有什么东西在自旋,只不过是粒子函数在电磁场中的表现出的一些特性罢了,也不用思考为啥转两圈只能算一周,我们只用知道每次进入磁场,带电荷属性的粒子函数就要被执行一次输出,函数代码需要根据自身的所谓自旋值随机输出一个运动方向。所以每用磁场来触发粒子函数输出一次,总会有一半向上,一半向下。下次再触发还是调用同样的函数,依然是这个结果,不会受上次调用的影响,所以永远没有确定的输出值。
量子纠缠发生在真实世界很诡异是吧,虚拟世界里到处都是这种现象,两个同时产生的宝箱,要是他们里面的道具出自一个概率表有严格的相关性,那么你把其中一个搬到游戏中任何一个地方打开也能马上影响另一个的结果,因为影响它们秉性的不是距离而是看不见的内部代码。
还有那个违背因果律的延迟选择实验,现实世界里感觉匪夷所思是吧,我们看看虚拟世界里这种事件一般都是如何处理的。法师发出一个火球,击中目标的概率为50%,那么是飞行到接触目标之前计算结果比较好呢,还是先按概率计算出结果,再反过来根据计算出的结果(命中/不命中)绘制飞行动画比较好呢。显然后者更合理一些,那么这就给玩家造成了一个因果错觉,玩家觉得是火球发出后根据目标的躲避情况来决定是否命中,而系统里其实早有结果,给玩家看的只不过是之前结果的表现。玩家要是突然决定在火球的飞行路径上再加一个检测点,好嘛,这个动画就得瞬间重画,从检测点开始再回归计算,因果律看起来就不正常了是吧,其实码农们都懂。
所以说出生在现代的学生们学习量子物理其实并不难,因为他们都有丰富的虚拟世界的体验经验,要是再学会一些网络编程,那更是容易理解。这些事情对于现代的学生来说,简直就是虚拟世界网游的现实翻版嘛。
如果人类只有科学,本也不该怀疑这些现象,因为客观观察到的事实是怎样,就应该理所当然的承认嘛。不过,幸好人类不只有科学,人类还有数学和哲学,这些知识是高于科学的,从而让我们能以超越当前客观世界以外的思考视角来审视这个世界。而我们人类的很多直觉其实也是来自这些知识,这也令我们对我们所处的世界产生了怀疑,难道我们真是在一个他人创造出的虚拟世界里吗?
那,假设真的是有人创造出这个虚拟世界,为何又会在量子层面露出这么多破绽呢?都满足我们的直觉不好吗?
其实,这事问程序员们就知道了。
为什么不事先在地图上把怪刷好啊,非要有玩家进去再刷?
因为要节省资源……
为什么要制造一些不可区分的道具啊,不能所有道具都有唯一的ID吗?
因为要节省资源……
为什么粒子的自旋值每次都要复位啊,不能记录下来吗?
因为要节省资源啊……
为什么粒子非要等观测的时候才确定状态啊,不能事先就生成好吗?
还是因为要节省资源啊同学,这个宇宙场景很大的,我哪能做到把全宇宙里所有粒子在每一个普朗克时长的状态都计算出来啊,既浪费资源也没有必要,你要看哪个我就算哪个不就完了,只要你不认真琢磨,看起来和全算状态其实没啥区别。
是不是很符合一个程序员的想法?
你现在是不是觉得物理学家们怀疑有人创造了这个虚拟世界是很有道理的?自然界的这些安排的确奇怪了,要是真的存在一个造物主的话,很多见鬼的现象就能解释了!
真的,只能这么解释。
============================
【第一次追更】
多谢大家热烈关注,那我们把这个代码构成的虚拟世界的科幻想法再搞完善一点看看。
假如你是个小码农,你的老板要你开发一些虚拟的拟真世界,你要怎么搞呢?
你想了想,决定先定义一些构成世界的夸克级的基本粒子,你构造了一些一维函数模拟出这些粒子的秉性,这就像“Minecraft”里面小块一样,只不过你用的形状是线条。
但是夸克太小了,就好像是像素一样,很难赋予太复杂的秉性,于是你开始用夸克拼装更高一等的基本粒子。用什么办法拼装呢,你构造了一些小块根据基础秉性相互作用的效应,并在代码里用方程形式表现出来,分别叫强相互作用和电磁作用。这些线条彼此靠近就会按规律黏着或者排斥,然后自动组合出更多类型的高等粒子的框架来。
线条搭建的粒子好像是基本三维容器,用来装承这些最小的一维函数,出于不可重复调用的原因,容器里不能装载属性相同的夸克(泡利不相容原理)。
然后,再设定一些函数之间的相互作用,先设定个与质量有关的,把引力方程写进去。
模拟两个粒子运动一下,嗯,跑的不错,任何时候把时间参数代进入马上就可以得到速度位置,用个微分方程就好。
可是物体一多就不行了,得迭代,多体问题没有解析解就只能求数值解。
这样计算方面就有一个问题了,那就是时间不能连续,得有个最小单位,而且得足够小。如果迭代步长太大结果误差就太大了,那么时间单位最小可以多小呢。
程序员研究了一下主机的参数,决定根据硬件条件的限制来定义,系统的最小时间片是多少呢?
是一个“普朗克时间”:1E-43秒,程序员发现定义完这个变量以后,很多参数也随之确定出来了,比如宇宙的最大速度 = 最小普朗克长度/最小普朗克时间,于是光速就有了。
分子为啥是要用最小普朗克长度呢,因为这个世界要尽量拟真嘛,要让物体运动的尽量平滑,能不跳格就不跳格。但是这事不能表现的这么直白,于是程序员研究了下,正好根据作用效应把粒子质量和速度挂钩起来,用质量来限制速度的上限,正好达到光速时候质量无穷大,从容器层解决了这个问题(洛伦兹变换)。
好了,搞定一些常数,程序员开始跑一个大规模的测试版本,模拟了几万亿个粒子的行为,系统就开始卡顿起来。
程序员有点头疼,这不省心啊,老板不肯投资升级主机,这才多少粒子,离模拟一个星系的距离还很久呢。于是他去请教一个老程序员。
老程序员看了下他的代码,冷笑一声,你这个搞法再多少计算资源都能给你耗尽了知道不,你看看每个粒子都在占用内存和CPU时间,彼此作用起来计算量是指数上升的,有必要吗?你要想想,中间状态有没有必要存在?
可是程序员犹豫了一下说,那也不能直接模拟到终局啊,到了最后肯定是热寂归零。
老程序员用报纸敲了一下他的头说,你程序跑给谁看的,客户在哪?
程序员这才想起来,老板之前指定了一个观察者接口的。对嘛,谁调用哪个接口就马上进行计算就好了。程序员重构了一遍系统,把粒子代码全部脚本化了,这样方便随时调用。然后把系统输出修改成针对意识接口的观察流模式,按照意识接口的调用来驱动计算输出。
这样,整个仿真模型的主循环就大大简化了,不用输出中间状态让模拟计算量大大下降。有了这个方向,很多问题就迎刃而解了,程序员搓搓手,是时候开始解决宇宙宏观架构的问题了,怎么才能稳定整个大框架呢,好像要搞一些新的物质形态才行,程序员又开始拼小块了,这次的目标是暗物质和暗能量,还有空间的属性问题……
欢迎码农们一起来开脑洞~~~
——————————————-
一些有趣的小问题
熵为何不可逆?
因为宇宙代码无法逆序执行,代码一旦开始执行,整个过程就不再可逆,输出结果也无法变回代码。
量子加密究竟是什么?
很简单,我们无法将代码执行后输出的结果逆转成未执行的代码态,比如一个随机函数执行输出结果后,我们无法拿着这个结果再把它变回随机函数。量子传输中的粒子只能被观测一次,观测后就变成了确定的状态,这和没被观测过是有区别的,我们发现这个区别就能知道信息有没有被人阅读过。就好像游戏里的宝箱开过了是无法还原的。
量子计算究竟是什么?
其实经典计算就是让“宇宙母机”运算之后,人类计算机再用确定的结果去运算。而量子计算则是直接调用脚本混合重编程,然后盗用了“宇宙母机”的算力来帮忙计算。比如,两个随机函数相乘,经典计算就是先运算两个随机函数得到结果,然后再把结果相乘。如果我们要直接乘积结果的分布,那就得重复计算几万次来看。而量子计算则是把两个函数的代码合并,直接在代码里完成相乘,然后把混合后的函数交给“宇宙母机”重新打包成一个新的随机函数,这样这个函数的输出结果就相当于包含了之前的多步计算,我们现在只用对这个函数的结果进行输出抽样就可以了。
量子计算的难点在哪里?
最难的地方就是保存和合并两个基本粒子函数的时候,不能触发运算调用,一旦触发,函数被执行就失去了代码重编的效果(退相干),而真正要完成有价值的计算,量子计算机需要合并几十个粒子函数,所以必须小心翼翼,还要排除误触发执行的干扰。
============================
【第二次追更】
再次感谢大家的热烈捧场,追更回复一些留言,并发表一点点感想哈
首先请大家不要过度上升本文的境界,这不是科学理论,只是脑洞幻想,答主也不是专业学者,只是业余科幻爱好者。我的主要目的是帮助大家理解一下现代物理学家的困惑所在,顺便帮大家科普科普晦涩难懂的量子力学,你看按本文的比喻,是不是量子力学理解起来感觉容易多了?
至于这些幻想是否有可能是真实的,我也只能耸耸肩。但是里面的内容确实和量子物理领域和量子计算领域的真正专家都偶有讨论过,虽然粗糙,但与现行的科学理论并无明显的违和之处,大家可以用这个角度来理解量子力学,不会导致走火入魔。
其实量子物理领域凡是涉及到哲学层面的内容,都是没法证伪的,比如意识的本质,平行世界是否存在,时光回溯有没有等等,非要比较的话,按奥卡姆剃刀原则,把世界理解成虚拟的说不定还是最简洁的版本。
但是,请不要因为世界有可能是虚拟的,大家就跑来问作弊码是什么,怎么卡BUG,怎么把系统搞宕机,怎么把缓冲区搞溢出!你们是在严重低估上层世界程序员的水准,能开发这个规模系统的团队能让咱们这种层级的存在把系统搞宕机?你就想象一下吧,如果你是主程,这个系统的鲁棒性会定义的多高?黑洞,超星系团都可以任意相撞,会怕人类造几个还没行星大的加速器?
就算退一万步讲,这个世界出BUG了,大家觉得那可能被你我知道吗?处理系统崩溃的运维手段不就是停机,打补丁,清档回滚数据,重启,完了各位能知道发生过啥吗?
还有一个重大问题是,如果真有造物主存在,他们开发这个系统到底想干嘛呢?
当然,我们是永远无法揣测更高维度的智慧在想什么,就像蚂蚁不能懂得穿白大褂的人在干嘛一样。但是这不妨碍我们换用自身的角度来思考下:如果人类可以创造出这样一个虚拟世界,并且能在其中演化出虚拟的智能生命了,人类会创造并且持续运营这样一个系统吗?
显然会,而且会运行非常多个!
因为这样做至少有几个对人类来说非常有意义的目的,我们来看看:
首先其实是很有趣。观察一个虚拟宇宙从诞生到演化,诞生生命到产生智慧,这是多么有意思的一件事啊,反复的模拟说不定可以看到各种各样的演化结果,这就像我们现在看着自己创造AI不断进化一样有意思啊,为什么不多看看呢?
其次,伴随虚拟宇宙的演化,AI的进化本质上和现在人工智能的进化学习算法是类似的,反复的进化我们可以得到更优秀的AI模型,这不就是自动学习么,这样的AI模型说不定未来可以用来解决一些更有价值的问题(比如寻找宇宙终极答案是不是42);
第三,AI的进化带给了我们更多的借鉴和思考,虚拟智能同样会在它们发展的各个阶段创造出五花八门的艺术,科学,迷信,政治,宗教,战争等等,而且会有各种各样有趣的创新和创意。这些文明的创造产物,对于更高的文明同样具有意义,观察研究虚拟AI社会的各种各样的演化现象和历史,简直就是在观察一个丰富的文明宝藏;
最后,这样的虚拟演化还有可能帮助我们寻求一些宇宙知识的答案。运行演化一个虚拟世界实际上就是在加速模拟真实世界的演化,我们观察AI的行为对理解文明的未来发展显然有莫大的帮助。
所以推己及人,如果人类未来会对创造并观察虚拟世界感兴趣的话,我们也可以认为更上层的智慧也会有类似行为(之所以用了更上层而不是更高等的说法,是因为我认为更上层的造物主也不一定就是智慧或者能力会远超它的创造者,就像未来我们肯定可以创造出我们自身更加聪明和智慧的AI生命一样)。
我们所处的宇宙很大,未来人类文明或许不缺物质,不缺能源,不缺空间,不缺时间,但是很可能会缺文明的同伴。费米悖论也许就是在提示我们,人类文明未来在宇宙中将会是完全孤独的。我们不知道自己为什么被锁在了这个没有别人的世界里,也许三体文明已经用曲率波把可视宇宙覆盖掉了,并把宇宙速度的上限限制在光速来永久的囚禁地球文明。也许人类文明玩的就是一个单文明虚拟游戏,我们是被分在单独进化组里隔离观察的对象。
但是有一点几乎可以确定的是,不管留给我们探索的环境有多大,未来人类如果发展的足够久的话,我们的科学最终总会碰到这个世界的根本性的无法突破的规则之壁。就好像虚拟游戏里的NPC永远不可能跳到键盘前一样,科学会碰到的是永远无法逾越的规则级的天花板,也许是无法跨越的空间距离,也许是无法再拆解的微观极限,也许是主观世界和客观世界的神秘界限,也许是人类不可碰触的更高时空维度,甚至可能到人类最信赖的数学都无能为力的程度,那是真正的边界。从这个角度来说,人类是不是被囚禁在一个虚拟时空里根本不重要,所谓囚禁只是牢房大小的差别,就像罪犯关在监狱,但是自由人被关在地球一样。
那么,无法发展的人类要怎么办,生存的意义何在?
这个问题同样可以拷问一个已经没有玩家的网络游戏中的NPC:你不过就是十字路口的一个路人NPC,你在这里存在的目的已经不存在了,这个系统也没有人在维护,只是在默默运转而已,你的存在对造物主也毫无意义,甚至造物主们早就忘记这里还有一个没有关闭的系统了,那么你能干什么?
文明自然不会轻易沉沦,就算面对绝壁文明也自然会懂得向自身寻找存在的意义。借用大刘的话,“给岁月以文明,而不是给文明以岁月”。
茫茫宇宙中,文明存在的本身就是意义,文明经历岁月就是对自身意义的不断证明。就算文明万一无法向外探索,但是不妨碍文明可以继续探究自身,艺术可以不断创造,历史可以永恒演绎,文明会在可触及的时空里精彩的存在着。试想有一天,宇宙这个游戏没有玩家光顾了,也没有人维护了,里面的NPC文明却继续过的非常精彩,他们在小小的虚拟环境里载歌载舞,种菜养羊,拍电影写小说,甚至自己动手改造着整个宇宙,还养出了一大堆的小世界和小文明,这是不是应该叫做就算看破了世界的真相,但是还是依然热爱生活的不屈文明呢?
所以我想,创造虚拟世界应该是每个文明发展到一定阶段都会做的事情吧。任何文明在无法找到自己的造物主并与之对话后,应该都会想把自己化做造物主来赋予自身更多存在的意义。说不定上层世界也是相同的情况呢?
哈哈,我知道大家又要反对套娃了。可是,哲学上讲我们本来就是无法去穷究任何问题的。造物主若有,那么又是谁创造它呢?既然从哲学角度讲对于任何终极问题的探寻都是永不可能有答案,所以我们不如好好关注当下,就像无人照料的游戏里的智能NPC,在失去外部意义之后,依然把每一段岁月都活出精彩,这或许才是生命,或者文明存在的最大价值。
好了扯远了,为这么个问题胡诌了这么多废话,实在抱歉浪费大家时间。
不过深夜偶感,愿有远友心有灵犀能共叹之。
============================
【第三次追更】
amz,居然两万赞了,实在没有想到无意中的一篇脑洞贴引来大家这么热烈的讨论。
感谢下各位知友的热情支持点赞,我也很高兴与各路大神们切磋交流,一起聊些与现实烦恼无关的哲科话题。
好吧,我继续回应一些近期的留言和私聊。
首先我没有过度曲读杨振宁教授的原意,我也不认为他所指的造物主就是某种神灵,或者类似宗教信仰的东西,我个人也不支持所谓“科学的尽头是神学”之类的说法。我只是就物理现象谈个人理解,可以当作码农+游戏制作者,从自身职业角度出发对量子物理领域作了一些业余科幻式的解读,就算我怀疑存在世界是虚拟的可能,也不会因此而抛弃依靠证伪精神质疑一切的科学思维方式,我不会因为自己的脑洞,就会昏了头把想象当作了不需证伪的信仰,我是一位坚定的科学思维方式的信奉者。
所以这些内容,大家当科幻来理解就好,不能证伪的想象就让它留在想象的领域吧,而且确实科学也不关心这些内容。所以咱们聊咱们的脑洞,不碍着科学也不碍着神学,请大神们不要太较真。
不过既然是科幻,也不妨碍我们认真一点哈,鉴于大家对我们的世界存在虚拟的可能性的各种讨论,我的看法是,如果真的要追问,感觉虚拟的可能性其实是相当大的,理由如下:
1 最直接的理由自然是来自费米悖论,我们这个星球的存在,包括人类的存在从任何逻辑角度来讲也太特殊了,而至今这个环境里空无他人的情况来看,同时对比宇宙历史和人类文明史之间的悬殊的时间关系,从逻辑上分析简直不可思议。按照宇宙学的最基本原理:“我们不特殊”来做出发点思考,随便做个数学模型推算一下,计算下一定范围内可能诞生文明的数量,在模拟下文明扩散的速度和宇宙年龄之间的关系,就知道人类现在这个奇怪的处境发生的概率能有多低,低到简直不可想象的程度;
2 我们所处的环境也太特殊了,为什么我们向宇宙的各个方向看去,星系的密度全部都是均匀一致的,完全看不出我们在宇宙的什么位置?你要说服我不要联想这外面是个系统生成的背景也很困难啊,宇宙唯一一个文明诞生在正好宇宙中间的位置?
3 现在对地球生命的各种演变历史也还存在大量未知和争议,进化论到现在也不能很完美的解释整个生物进化的路径,先不说整套地球的生物体系完全是在几千万年自然进化发展而来的证据说服力强不强,但我如果按我的职业角度,请上几位资深的游戏策划来阅读一下地球生物的分类学,他们倒是一定会有一些非常熟悉的感觉,这种感觉就像在读一套非常有目的设计文案。整个地球生物的谱系其实充满了浓郁的策划设计味道,就像解读量子现象一样,有些地方甚至巧合到了难以置信的地步。当然这个脑洞开起来就更复杂了,有机会再开贴扯淡吧;
4 更重要的一点是,人类马上就会创造出属于我们的虚拟小世界了。按照现在人类计算技术的发展速度,用不了一百年,我们估计就可以做到完全的将意识数码化,从而完全的从技术角度理解意识的本质,并学会如何创造具有人工意识的智能AI。这应该比人类大规模定居火星要更早实现,而且伴随量子计算技术的发展,在虚拟环境里创造真正的元宇宙也指日可待。我不期待五百年内人类能到达比邻星,但是这之前实现出一个虚拟宇宙则大有可能,也许刚开始我们只能模拟星系级别大小的拟真环境,其他都得用贴图,但是几十个版本迭代下来,这个环境显然会越来越逼真,而且其中模拟的文明应该不会在意这个问题,因为他们看到的客观世界是怎样的他们都会全盘接受。
同样根据宇宙学原理,推己及人,如果人类文明建立才几千年就能向下创造虚拟世界,那么虚拟世界的嵌套速度将远胜过文明在物理层面传播的速度。从直觉上想象一下就能知道,人类文明所处在一个虚拟环境里的可能性真是超乎寻常的大,甚至我们都不知道我们到底在第几层,这个神玩法一旦开始,恐怖叠上几千几万层也是稀松平常的事情。我相信,人类没有那么幸运,别说正好我们就是能接触真实物理世界的原始文明,就算运气好在头一两百层的机率可能都不是那么的大。
每个文明都在笼子里,每个文明又都在造新的笼子,层层叠叠也许才是我们这个宇宙的真相。不信,再等几百年看看人类能搞出什么东东来。话说一百多年前,有杂志邀请很多当时的学者一起畅想未来,预测未来人类会做出那些成就。有人预测,人类会造出几千层的摩天大楼,天空城市,无数的飞行汽车穿梭其中,人类还会定居在月球和火星,开采太空的能源和矿物。结果,一百年到了,人类并没有干这些事情,人类主要成就是造了互联网,并升级成了移动互联网,创造了Facebook,Twitter,Wechat,Youtube,Biliili,Zhihu,并乐在其中。
再等五百年,你们猜人类在干嘛?
============================
【第四次追更】
(好生气,刚写完追更居然突然丢失全部内容,这是有力量在阻止我公布真相了,那你要失望了,我熬夜也要把这更补回来!)
有朋友留言对量子实验的具体诠释内容感兴趣,这次追更我们就挑一个经典的量子实验来尝试用游戏式的方式来诠释一下看看吧。
我们来看一个经典的基本量子实验:惠勒延迟选择实验。“延迟实验”是由爱因斯坦的同事约翰·惠勒提出的,也是传说中的世界观颠覆者,人生观毁灭者,因果律杀手,理科生躁郁症的重大致病因素之一,毁人不倦的经典实验。
为了方便不太了解该实验的朋友,我花一点文字把实验的具体设置和过程描述一下,如果熟悉的高手们尽可略过。
如图所示,该实验的具体布置非常简单,一共只用到七件主要的实验仪器,分别是单光子光源,半透镜O,全反射镜A和B,半透镜C和两只接收器(探测器)。所谓半透镜,就是一种半镀银的透镜,有50%的概率会反射光线,50%的概率会让光线直接通过。
我们先看图,我们先不在C处放置透镜和接收器。如果这时从光源处发射一只光子,那么光子会怎样传播呢?不太熟悉量子物理的朋友可能会说,那光子应该50%概率走上边,沿着OAC路径传播,50%概率走下边,沿着OBC路径传播。这样说也没错,如果现在光呈现出粒子特性的话,的确会如此。
但是,我们都知道光具备波粒二象性,它还可能像波一样传播。如果像波一样,那么光就会同时走上下两条路径,同时到达C点。这时候,如果你在C点放置一个屏幕的话,同时沿着两条路径到达的光波还会与自身发生干涉现象,在屏幕上呈现出干涉图案来。
那么,光到底会呈现出粒子特性还是波动特性呢?答案是,取决于实验者所采取的观测手段而定!
如果实验者在OAC或者OBC的路径上放探测器,检查光子具体从哪条路径传播,那么光子就马上会呈现出粒子特性,只会从一条具体的路径传播,在C点屏幕的干涉图案就消失了。而如果我们不去检测光子走的哪条路径,故意忽视光子的路径信息的话,光子就会呈现波动特性,干涉图案又出现了。
说到这里,可能不熟悉量子力学的朋友已经有点纳闷了,为什么观测的方式会决定光子的行为,光子又是如何得知我们会怎样观测它呢?但其实,这还不是这个实验最离谱的地方。科学家们决定再将实验推进一步,科学家们决定让光子先出发,等光子已经经过了透镜A或者B之后,再决定如何观测。
具体的做法就是在C点,我们再准备一个半镀银的透镜和两只探测器,然后我们就可以先等光子发射,然后精确的控制时间,计算光子的飞行时间,等到光子已经经过了A或者B点之后,再决定是否插入C半透镜,那么现在就可能有两种情况:
1. 不插入C半透镜,那么检测器可以准确的了解光子从哪条路径而来,光子呈现出粒子特性,只有两个探测器检测到光子的概率均为50%
2. 插入C半透镜,那么不同路径而来光子再一次经过了半透镜的概率反射,我们将无法判断光子具体的路径信息,光子就呈现出了波动特性,并在C点发生自我干涉,经过调整可使一边的探测器始终能检测到光子。
这样,我们就可以不同的探测器输出模式来判断光子究竟展现的何种特性,以及插入C半透镜有没有影响光子之前的行为。结果实际实验中先发生的光子行为果然非常诡异和后发生的观测手段完美匹配了起来,实验说明实验者在C点插入半透镜的行为虽然在光子经过AB点的时间点之后,但是却影响了光子在整个传播过程中的特性表现。这就好像是两者之间的因果关系被倒置了一般,我们居然用置后的观测手段的改变反过来影响了之前发生的光传播事件,真实世界为什么会发生这种事?
从实验逻辑上来看,实验中事件发生的顺序似乎是这样的:
单光子发射 → 经过半透镜O → 经过镜子A或B → 半透镜C被插下 → 回溯修改传播路径 → 经过半透镜C → 到达探测器
这已经完全不能理解了是吧,而且科学家们还在此基础上继续推进了一步,他们决定将实验中OA和OB的距离继续加大到星际空间的尺度,采用引力透镜来代替实验中的普通透镜。结果大家猜怎样?实验结果果然与距离大小无关,光子依然我行我素。
不过在这个实验里,将尺度放大到这么夸张的地步后,给人的感觉就非常毛骨悚然了。假设OA和OB的距离有一百万光年,那会发生什么?也就是说,我们可以等光子发射后,飞行了快一百万年之后,再决定是否插下半透镜C,观测手段一旦改变,光子就得去修改之前一百万年的传播路径,这可以想象吗?那么,这漫长的一百万年的岁月里,这颗光子究竟在哪里呢?是同时在OA和OB吗?还是哪里都不在呢?它怎么有能力去改变百万年前发生的事情呢?
好了,我们先放下这个细思极恐的问题,来看看游戏版本的延迟实验诠释吧,也许世界还有救。
我们先定义下这个游戏的开发需求:
有一位会发射隐形火球的法师,他发射的隐形火球既能像粒子一样飞行,也可以像波一样传播,至于究竟什么时候会怎样我们先放一边。
接着我们又设计了一些道具,包括两块可以一半概率反射火球法术的魔晶O和C,然后还有两个魔法反射镜,两个当做目标的挨打小精灵。好了,按图摆好位置后,一个魔法版的延迟实验我们就可以布置出来了。
接着,我们抓了一位码农,让他来完成这个实验的整个过程。
码农愁眉苦脸的琢磨了一会后,考虑到计算资源的紧张,他发现他不能无止境的计算火球每时每刻的位置和状态,这样做既消耗资源,又没有意义,他应该在关键时刻计算火球的命中结果就好了。
那应该在什么时候进行计算呢,码农分析了一下火球飞行的全过程,他发现有几个时间点可以选择:
第一个时间点就是火球刚刚发射的时候,这时候发射路径方向已经确定,因此全路径情况系统基本都已经得知,但是缺点是在火球飞行的过程中路径上的情况随时随地都会变化,所以系统需要关注路径上任何变化,这样计算量比跟踪火球还大了,所以此时计算过早了;
第二个时间点是路程中遇到交互事件的时候计算,比如遇到魔晶,或者中途跳进来的小精灵等等,但是这种事件太多了,比如说火球碰到了空气中的灰尘算不算呢,如果可能事件这么多,连续进行跟踪计算岂不是和实时计算也没区别了,起不到节省资源的作用。那么能不能找个时间统一结算呢?那什么时间统一结算最合适呢?
码农思考了一下感觉应该在观测之前的最后一刻计算最好,因为这样计算不会漏掉任何路径。所以码农选择了第三个时间点,也就是观测前的最后一刻进行火球飞行的全路径结算。
码农决定这样来安排整个实验的事件过程:
1. 先计算出火球的飞行路径,遍历所有会到达目标点(观测点)的可能路径,然后播放火球发射动画;
2 系统每隔一个普朗克时间就判断下所有路径上火球应该到达位置上有无观测事件发生,如果没有的话系统就继续idle,进入空闲等待状态;
3 一旦当系统检测到有观测事件即将发生以后,立刻根据观测点位置回溯检查传播路径上的所有交互事件,并进行概率计算。因为系统并没有记录任何过程变化,所以系统只能用当前的路径情况进行计算。又因为现在是用概率进行叠加计算,所以再小的路径概率也会叠加进来,而不会被丢弃。系统会回溯观测点到发射点的所有可能传播路径,并以当前的路径情况以波函数的形式把传播路径上的一切交互事件全部混合一起进行概率计算,以得到最后的总概率函数;
4 系统根据最后计算出的最终概率输出观测结果,最后再重置火球的函数。
码农测试了一下,按这个终点结算的算法非常节省系统开销,而且结果误差也很小,完美实现了客户需求。唯一的问题就是在最后计算的时候,因为系统已经没有火球飞行过程中路径的变化信息了,所以只能以最后一刻的路径情况来进行概率结算,但是与节省的资源相比,这点小破绽还是可以容忍的。
现在大家是否明白了,码农的这个算法其实非常省事,他并没有关注火球(光子)在传播过程中遇到的任何事件,他默认到检测点的时候当前的路径情况就是火球(光子)在飞跃过程中所经历的实际情况,这样的做法在玩家看来当然会出现因果倒置的错觉,因为玩家在路径上那些趁火球(光子)飞过之后做的事情其实毫无意义,因为码农只到最后才结算全路径的概率,所以,火球(光子)击中目标那一时刻路径的现状才是真正能影响最后结果的。而之前发生的任何事件,都被系统无情的忽略了。
之前玩家在插入魔晶C的时候,以为火球已经越过了AB魔法反射镜,正在前往魔晶C的飞行路径上,但我们现在知道了,这个所谓飞行中的火球只不过是玩家的想象而已,它并不存在,而这个过程中系统后台其实什么都没干,只是在发呆和等待而已,玩家那些插来取出的行为其实都只不过是瞎忙活而已。直到后台发觉火球马上就要击中目标点小精灵的最后一刻,才会把最新的路径情况代入到火球的波函数里计算出最终命中概率,并进一步得到最终粒子位置结果。
所以这个算法中,有交互(观测)才有输出,和外部无交互的时候,系统idle就好了,用不着时时刻刻的去移动火球位置,也不用时时刻刻更新火球的状态。所以在每个火球的交互行为(被观察)之间,火球没有任何行为发生,它只待在代码里,等待观测事件的发生而已。
这个看起来很偷鸡的算法,其实很好的反应出了一个称职码农的技术修养,一个优秀的程序员肯定是只关注用户所需要的输出结果,所以系统在没有观测事件的时候,当然没有必要将一个物体在三维坐标系里移来移去浪费系统开销,一切粒子运动过程在码农眼里都毫无意义。就像设计FPS游戏一样,玩家开枪的时候给他画个开火的动画,然后根据距离算算子弹飞行时间,等到了时间再根据实际情况算下命中概率和位置,如果命中再画个击中动画就好了,子弹飞行过程?不存在的
所以,这个世界上其实也没有什么光子在飞行,光子被发射后就不存在实体了,有的只是宇宙母机的系统在后台默默的计时和轮检路径事件变化而已。光子也不用千幸万苦的耗费百万年的飞行路程来到我们眼里,或者来到天文台的望远镜的底片上,这些事件在我们抬头仰望星空的时候,就已经被合理的插入到某些粒子的事件序列里了,到了该执行的时候,交互事件就会自然触发,而你眼睛里的视神经细胞就会感受到事件的影响结果。
所以每个微观粒子的飞行运动过程,其实都是系统在后台不断刷新一个未来待执行的路径交互事件序列而已,只要事件还未被执行就可能因为环境变化而改变,所以随便科学家们把路径上的透镜插来插去都没关系,系统最终只会以事件执行前最后一个普朗克时间时事件的刷新结果来执行输出,光子也不用那么劳累隔一会就要去回溯更改历史。那一百万年,它哪里都不在,只有系统在后台假装它在飞行穿越空间而已。
各位码农们,你们是否也认为这样才是最合理的算法呢?
这是一个神奇的思想模式,一旦你们开始用程序员的思维理解量子行为后,很快就可以给各种量子实验加上算法解释,包括什么魔术擦除实验,什么量子纠缠,什么双缝干涉,还有什么猫猫狗狗的,观测者难题也迎刃而解,整个世界顿时全然不同。
熟悉量子力学的朋友也可以来比较下你所知的延迟实验的诠释和游戏版本的相比如何,拿起你的奥卡姆剃刀来挥舞下,看看谁更简洁易懂?
现在,是不是你也觉得这个世界有点不太真实了?
============================
【第五次追更】
又来追个更了,既然我们的脑洞已经开到这个程度了,大家还在热烈关注本话题,那么看来只好把我们的洞继续往深处挖挖看罗
续接前文说到,我们已经反复讨论了假设世界虚拟化的可能性,那么如果真的这个世界是虚拟的,对我们有什么帮助呢,比如说我们用程序员的思维能获得更多对当前世界的理解吗?
更有价值的内容暂时也没有能力去推演,不过我们还是可以从理解量子力学的角度来看看,用程序员思维我们能不能够更理解量子现象呢?
比如,光为什么会具有波粒二象性?
从程序实现的角度思考,光的本质就是概率+波动方程编写出的一个算法函数。在光传播中触发的交互事件在不被观测的时候,宇宙母系统(后面我们简称系统)就会默认事件只有发生的概率而没有实质发生,那么一切事件都会先叠加成一个类似脚本的执行序列。一旦我们进行观测,该脚本就会立刻被执行输出具体结果,光子也看上去就有了具体的位置,表现的更像粒子了。而之前脚本叠加的阶段,则充分展现了波函数的特征。
我们理解这个逻辑之后,也可以用来做一些思想实验,比如我们尝试在延迟选择实验基础上多搞一些花样看看。
比如说:我们可以在惠勒实验中,等待光子发射之后,计算时间在其经过了半透镜O之后,去改变O的反射率,将反射率从50%调整为30%(我想通过某些液晶技术应该可以实现瞬时的调整吧),那么在C点再进行观测的话,光子走OAC路径和OBC路径的概率会发生变化吗?
答案应该是会,因为概率计算只会以观测前最后一刻的路径信息为准,在观测的时候透镜的反射率是多少,光子在不同路径的传播概率就应该是多少。
我们还会发现在光子传播的整个过程中,系统基本只记录和叠加各种交互事件概率,输出都是等到最后观测的时候才发生。为什么这个宇宙系统不喜欢记录具体的数值,而只记录概率呢?
因为这套处理体系不擅长记录具体精确的数值!
如果我们把粒子看做一个计算函数的话,我们会发现系统记录粒子的精确数值,包括各种内禀属性,位置,速度等等的能力非常弱,每类属性只能保存一个当前值,一旦刷新的话,之前保存的值就会被丢弃。
而且粒子函数里保存的带精度的数值之间还需要共享有限的储存容量。如果我们要求某一个值输出的足够精确的话,其他数值就无法保持精度了。比如速度和位置这两项就共用了同一个输出字节空间,某一项输出占用的小数空间太大,另一项就只能被迫减少小数位数,这就是所谓海森堡的测不准现象,我怀疑这套算法在设计的时候似乎并没有考虑到有人会要求输出这么多项精确的数值结果。
但是反过来,这套算法保存概率和处理概率运算的能力却非常非常的强。
粒子在各种交互事件里发生属性改变的概率,只要不要求输出结果,系统都可以瞬间完成概率的各种改变和运算。
所以,我们用这种特性制造出来的量子计算机也同样如此,量子比特非常擅长保存和运算概率,但是具体的数值却需要依靠经典方式来存储。而这种概率的叠加过程计算,用经典计算机来模拟就非常的消耗资源了,因为需要不断的记录海量的中间状态,且计算量随着粒子和事件的数量指数上升。
模拟宇宙的这台超级母机也是量子的,所以它非常讨厌具体数值,讨厌追求精确。在它擅长的这套处理模式下模拟出的整个宇宙其实是一个以时间为轴,各种粒子不断叠加交互概率的混沌汤。无数的粒子不断的产生,运动,碰撞,分裂,相互纠缠,退相干,湮灭,这个过程中无数的概率事件都重重叠叠的记录到个每一个粒子的函数内部里,这整个宇宙就是一大个无比复杂的概率演算场,而概率其实才是这个宇宙的最底层最重要的数学机制。
有人说,这个体系似乎也很讨厌观测者的存在,观测者不断的打断系统自然的概率演算,不仅要求输出结果,还要刷新粒子状态。那如果观测者太多的话,是否会导致系统效率下降呢?
要思考这个问题之前,我们需要了解清楚的一个问题是,你怎么知道这个系统里究竟有多少的观测者呢?或者进一步追问,怎样才算观测者呢?
不熟悉量子理论的朋友经常会问类似这样的问题:在量子世界里,怎么才叫做观测?婴儿看算吗?动物看算吗?摄像机看算吗?AI看算吗?
比如,在薛定谔的猫这个思想实验里,有只鹦鹉在盒子里看到了猫的状态,这算观测吗?
其实这个问题的答案很简单,如果一只鹦鹉看到了,但是它无法说话,不能告诉你的话,那么这只鹦鹉就和盒子里的即死又活的猫就一起进入到一种量子状态了,准确说是鹦鹉看到盒子里的情况后,脑子理解后发生改变的部分加入到这整个量子的波函数体系里去了。对于你来说,只要你无法知道具体的信息,那么无论谁看了都没用。
所以整个世界里发生的量子事件,对你来说谁看到了都不算观测,如果没有最终告诉你的话,那么一切和事件相关的人或者事都只是继续卷入到概率事件中而已,而你才是最终坍缩一切量子态的终结者!
神奇吧,你就是这么的优秀,你才是(你的)世界的唯一的主角!你玩的,其实是一个单机游戏,你没有玩的内容,都只是不占资源的静态代码而已。现在你不担心系统会被玩崩了吧,所以大家放心生娃吧,就算无限增加人口数量也不会拖慢系统效率的。
这还真不是胡扯,在量子物理学里,这个概念有个名称叫做“人本原理”。说白了就是一切你无法观测的世界与你无干,你只会存在在你可以观察的世界里,你的主观意识才是推动世界真实存在的唯一原因。
(不信?你试试用枪对准自己脑袋来一发,保证不会死。因为你因为死亡导致意识消失的话,那你就不会存在在一个没有你的意识的世界里。只要有任何极小的概率导致你不死,那么你必定会存在在那个世界里,在你的世界里,你当然会活得好好的。)
看过这段话的朋友请务必不要相信,切切不要在我的世界里尝试自杀,也不要因此就走上了挑战极限运动的道路,在我世界里你真的会死的,而我不保证你还有存活的概率,请不要让我因此产生愧疚感。
好了,很晕是吧。这也可能就是量子物理发展下去最终会撞上的无解的哲学壁垒:主观与客观的认知之墙。究竟这个世界到底是在我们的主观认知里存在,还是真实的客观存在呢?换个说法,我们究竟玩的是个单机游戏呢,还是个网络游戏呢?物理学到这里已经无能为力了。
我们身处在这个世界之中,受到这个世界的规则约束之下,可能永远也不能真正得知真相。我们无法顺着网线爬到另外一台终端前看看有没有活人在操作同一个游戏里的角色,我们每个人都无法跳出我们当前的世界维度来认知和理解这个世界,这可能就是人类科学发展的真正极限所在了。
幸好我们的科学不关心此事,科学从来不去研究这些所谓终极的,本质的,不可知的,而又毫无现实意义的问题。科学只研究当下我们所能理解的客观规律,哪怕我们玩的是个单机游戏,那也当做网络游戏来看待,哪怕客观世界并不存在,我们同样还是当做客观世界来看待。科学只关心对我们有帮助的东西,管它究竟是虚幻的还是真实的。
所谓科学精神,其实是一种哪怕真相很可怕,甚至永不可知,但是我们还是满怀希望去探索可知的文明生存哲学。依靠这套哲学,人类哪怕永远无法突破当前的世界维度,也同样能享受文明存在的价值和意义!
是啊,多好的世界啊,与其痴问上天,不如认真在这个红尘里打打滚。
============================
【第六次追更】
好久好久没有更新这个回答了,后面又有很多朋友留下很多有趣的回复,翻看时候我也想到一个同样有趣的现象,所以今天来继续跟进更新一节。
因为有玩家问除了上面举例的延迟选择实验,还有没有其他的类似现象能用虚拟世界的设想来诠释?我认真思考了一下。
其实,几乎所有我了解的量子实验都可以用类似的思想来解释,但是因为过于复杂,不利于大家理解,所以我不想再描述更复杂的量子实验了。但我最近正好在看一些游戏类的帖子,在看到一篇有关3D游戏的帖子的时候正好想到了一个类似的对应现象可以谈谈。
而这个现象涉及到量子的另外一个诡异的行为,这个诡异行为就是所谓的“量子隧穿效应”。
所谓量子的隧穿效应,就是指粒子在某些尺度下,会随机的直接越过一些高能的位势垒,通俗说就是穿墙而过了。只要墙壁足够薄的情况下,基本粒子靠近墙壁的时候都有可能概率直接穿过临近的墙壁屏障而出现在墙壁的另一边。这听起来自然也是违背常识的,为什么尺度小的一定程度,阻挡对于粒子来说就可以偶尔消失掉?这在经典物理学中是无法解释的,一个小球想要穿过哪怕是极薄的纸,也不可能既不付出任何能量,也不弄破这张纸。可是在量子世界里,粒子就是这样诡异的越过了足够薄的障碍。
也正是存在这个隧穿效应,才导致我们现在的微电子芯片技术发展到1nm时代就碰上了继续缩小尺寸的物理学障碍。芯片里阻隔电子的材料如果尺寸小到5nm以下,量子隧穿效应导致的漏电现象就不可忽视了,如果尺寸进一步减小,那么漏电问题将更加严重,从而导致芯片的逻辑电路无法正常工作。这个问题已经成为芯片技术继续发展需要克服的最大障碍了。
当然,反过来,科学家也利用这个效应开发了很多具备实用价值的应用。比如隧道电子扫描技术等等,利用隧穿效应制作的隧道扫描电子显微镜可以帮助我们看到原子尺度的微观世界,这充分说明量子隧穿效应确实是真实存在且已经直接进入到日常技术的应用领域了。
不过我们的重点是,怎样理解这个效应呢?如果按照量子理论的一些传统理论,是用量子具备不确定原理来解释,量子具有一些不确定的能量,偶尔它们可以从虚无中凭空“借”到了一些能量,然后借助这些能量就越过了墙壁,从而实现了凭空穿墙……是不是听起来也很玄幻?
好了,那按本文的习惯,我们先看看游戏中有没有这个现象。
游戏中不仅有,而且还相当的普遍!游戏中的这个现象简单说就是3D物体的运动穿模。
什么是3D物体的运动穿模呢?就是说,在3D游戏中,运动物体有时候会在碰撞的时候穿过障碍物体,或者是穿到地形里面去。
这其实是一个游戏BUG,为啥会出现这个现象呢,3D游戏的程序员都很清楚,这其实是一个碰撞检测算法的精度问题。在3D游戏里,运动物体看上去像是连续运动的,比如一辆汽车,或者一个火球,但实际上呢这些运动物体的位置却是间断更新的,因为在计算机的计算过程里不可能有什么真正连续的事件,任何运动其实都是离散的。
就像在游戏中被投出去的石头虽然程序是用抛物线方程来计算飞行时间和位置的关系,但是实际上石头的位置却不是像理想抛物线一样连续的,石头在飞行中有没有碰到某个物体却必须要隔一会才能通过检测它和其它物体之间的相对距离关系来判定。而这个检测时间间隔就是碰撞算法的循环时间间隔。如果这个循环时间间隔设置的太大,那么就可能出现石头在上一次检测的时候还没有碰到物体,而下一次检测的时候已经穿过了物体的穿模BUG现象。但是系统是不可能把这个时间设置成为无限小的,甚至不能设置的太小,尤其是在多物体运动的场景下。因为在同一场景下,运动的物体越多,那么需要检测的相对关系就越多,系统需要检测每个物体和其他所有物体之间的相对位置,而这个检测数量显然是运动物体的数量的阶乘关系,所以每多一个运动物体,那么计算量就会上升一个数量级。这其实也是3D游戏中一个重要的算法优化问题,在3D游戏里,往往需要用各种二叉树四叉树来不断的优化碰撞算法以尽量减小指数级上升的运算量。同时在游戏团队里,3D游戏的关卡策划们也知道不要把运动物体设计太多,还有不要把运动物体设计的太小或者过大,错误的需求不利于减少运算量。至于到底能设计多少就非常需要经验了,所以往往会有些还不懂行的新策划在一通天马行空的乱设计后承接到了来自程序员的致命怒火。
那说回我们这个现实世界就很有趣了,现实世界里大多数我们肉眼可见,甚至显微镜可见的领域里,物体相对运动时候都呈现了非常良好的碰撞关系,完全符合牛顿力学的经典描述。但是,如果我们这个世界是虚拟的,往极限上去想,就一定会到最后出现算法精度覆盖不到的现象。果然,到了量子尺度下,这个现象出现了!
这就是所谓的量子隧穿的真正原因,这个虚拟宇宙的开发者没有考虑到(或者觉得没有必要考虑到)我们会去观察如此之小的尺度下的运动碰撞现象,虚拟宇宙里的碰撞算法的检测精度也是有极限的,当两个足够小的物体靠的足够近的时候,粒子的基本运动就会导致穿模BUG!于是,隧穿出现了,量子毫无道理的出现在了墙壁的另一边,这不是依靠凭空借来的能量实现的,这只是系统觉得没必要用更小的时间间隔来检测粒子的碰撞事件。
从算法角度上思考,其实我们也可以看出来隧穿的几个特点:
1 虚拟系统里的碰撞算法检测的循环时间肯定是远大于宇宙最小时间单位“普朗克时间”的,因为循环里还需要容纳大量的检测运算过程;
2 隧穿肯定是概率性的,因为量子位置输出因为有精度限制,所以存在随机,检测结果在一些边界情况时自然也有概率性的结果。但是,墙壁越薄,出现的概率自然也就越大,这很好理解。
最后,我们来看一个隧穿效应里面最难以解释的现象:”超光速隧穿“。根据量子理论中能量时间的不确定性原理,量子穿越屏障的时间和屏障的能垒高度是成反比的,也就是说,屏障能量越高,穿越时间反而越短,如果这个屏障的宽度足够的话,那么足够高能的屏障就会导致粒子以穿越光速的速度穿过了屏障,这和相对论中指出的光速是宇宙最大速度就冲突了。
理论物理学家们就这个现象争论不休,并且提出了各种各样的新的假设和说法来解释这个现象,试图一方面要坚决捍卫光速是宇宙速度绝对上限的地位,另一方面又要能解释出量子超光速穿墙的现象是咋回事。这些先进理论弯弯绕绕复杂无比,一般人建议不要去了解,以免出现头脑过载的症状。所以我们这些凡人还是回到地面来,想想看怎么用我们初中二年级的水平来理解这个最尖端的科学问题吧。
其实,这个问题同样也可以抓一个游戏程序员来拷问拷问。
比如,你是某个网络赛车游戏公司的老板,今天你很生气,因为游戏里某条赛道的最新成绩被刷新到了一个恐怖的令人惊奇的地步,有玩家只用了几秒钟就完成了比赛,很显然这是游戏出现BUG被人利用了,于是你叫来了游戏的运营经理和研发经理开会。
“你们谁来跟我解释一下,这个变态的成绩玩家是怎样做到的?”你作为老板有权要求下属们给你一个合理的解释。
运营经理连忙回答:“我了解过了,这是玩家利用BUG实现的。”
研发经理感觉很奇怪,说到:”应该不可能啊,这种BUG理论上是不可能出现的。”
于是你问道:“为什么不可能出现呢?”
研发经理说:“因为我们游戏里的赛车其实是有速度上限的,无论玩家怎样改装赛车,都不可能超过这个速度上限。”
“为什么不可能超过上限呢?难道玩家没有某种手段绕过这个限制吗?”
“不可能绕过的,因为这个速度上限并不是我们为了防止玩家刷BUG设置的,而是我们游戏的底层机制决定的。因为赛车在我们游戏里运动需要不断的改变位置,而我们游戏里面物体改变位置的最小单位和最小时间单位都是确定的,所以从理论上就会有一个最大速度,玩家无论用什么办法都不可能让赛车超过这个速度。因为这个速度就是我们游戏能保证赛车连续运动的极限,再快,赛车在玩家眼里就会出现瞬移了,这种现象从我们的底层算法上就是无法出现的,我们的赛车在程序空间中,只能一格一格的移动,不能跳格!”
你听完,觉得研发经理说的很有道理,于是就非常疑惑的问运营经理:“那么我们的玩家是怎么做到的呢?”
运营经理说:“我也不太懂这个原理,但是我能把玩家的操作重现给你们看。”
于是运营经理进入游戏,选择赛道开始比赛。只见运营经理在赛道上找到一个合适的位置,飞快的把车撞进了路边的一个崖壁,经理试了几次后成功了。某一次几乎是一瞬间,车没有被崖壁正常的弹回去,而是从另外一边的崖壁被飞快的弹了出来,这个穿越过程似乎没有花费任何时间,于是经理就重现出了玩家的变态成绩。
办公室里一阵寂静,你和研发经理两人面面相觑。
研发经理毕竟是211毕业的高材生,他想了一会就恍然大悟道:“原来是这样,我实在没有想到会出现这种情况,这其实是赛道旁边的崖壁太薄了造成的。”
“崖壁太薄为什么造成这个BUG?”你一脸的疑惑。
“是这样的”,研发经理已经完全理解了问题所在:“我们游戏里面的碰撞检测是有时间间隔的,程序会每隔一会检测赛车模型的中心和各种阻挡物之间的距离关系,一旦距离小于某个值就会视作发生碰撞,将车弹回去。但是这个崖壁阻挡太薄了,玩家的车速高到某个程度的时候,撞进来又正好在两次检测的空隙之间的时候,车的中心就穿过了这个崖壁才被检测到碰撞,但是因为模型已经越过了崖壁,于是碰撞程序就把车移到了另一边,所以赛车就穿墙而过了。这个移动是碰撞算法造成的,和正常的移动不一样,所以没有受最小移动距离的限制,所以就超过了游戏的最高车速。”
“碰撞算法有这么高的能力,能帮助赛车超过游戏的最高运动速度?”
“是的,游戏设置最高运动速度的底层原因是因为物体不能在空间中超过最小单位作跳跃,否则就会出现瞬移,如果有瞬移现象,那么就可能出现两个物体同时瞬移到同一个位置的可能。所以要求物体连续运动的本质上也是避免不同物体会同时出现在同一个最小空间单位里。但是,碰撞算法的底层原因也是为了避免不同的物体同时出现在同一个空间里,所以,游戏存在最高速度其实并不是原因或者目的,而是只是现象,更本质底层机制的其实避免不同物体的空间重叠,所以一旦出现这种空间重叠,这时候弹出物体几乎是不需要所谓速度的,系统会以最快的节奏把模型瞬移出去。当然,也不是完全无时间消耗的瞬移,重新绘制物体还是要花费一点时间的,但这也远超最高速度了。“
“哦”,你和运营经理总算弄明白了这个BUG的底层原因,于是你又问道:“那我们要怎样避免玩家再利用这个BUG呢?”
研发经理想了一下说:“很简单,把墙加厚点就行了。”
运营经理有点质疑:“这好像没有从本质上解决问题吧?”
研发经理耸耸肩:“这就是最省事的办法了,如果你觉得要从底层来彻底解决这个问题的话,首先我觉得没必要,因为减小检测间隔会极大的增加系统的负担,需要买更强大更贵的服务器,而且绝大多数情况下对玩家体验也不带来什么明显改善。其次,修改底层算法风险很大,搞不好会把整个游戏搞宕机,老板你看呢?”
“去让关卡策划和美术把崖壁改厚点,顺便检查下还有没有其他赛道需要修改。”你感觉作为老板,决策起来一点难度都没有。
在结束会议之前,你有点不放心,又问了下研发经理:“你确定崖壁改厚了,就不会再出现这个BUG了吧。”
研发经理一看就是一个很严谨的人,他斟酌了一会说:“理论上,还是有穿过的几率,因为我们的检测时间也有随机性,只要玩家尝试的次数足够多,再厚的阻挡也有穿过的概率,只是这个概率极小极小。”
“好吧,那就这样吧”,你作为老板深刻的理解不要为极小概率的事情去发愁的简单道理,这种问题,留给知友们去操心就好了。
虽然上面的场景对话是我虚拟出来的情节,但是大家应该明白这段对话指的是什么。从上面程序员和老板的对话中,其实我们得到了一个非常惊人的看待宇宙基础规律的视角,比如我们可以不把光速是当前时空速度上限当作是一种最底层的初始规律,而是把它视作一种现象,那么这个宇宙必然还有更底层的规律导致了这种现象的出现。
除了光速,我们甚至可以用类似的角度来看待物理学中的各种基础常数,尤其是那些有量纲的常数,它们很可能不是绝对不变的宇宙初始变量,而只是某些更底层的物理规律导致的一种结果。比如电子的电荷数值,或者质子的质量等等。
从另一方面来想,既然我们感觉常数之上还有更底层的规律,那么常数绝对不变也不是那么不可挑战了。就好像光速,虽然在底层上有普朗克长度和时间做为计算基础,但是更基础的约束很可能来自宇宙要绝对避免不同物质在相同时空的重叠可能,那么在某些特殊的情况下(比如量子尺度运算精度不足造成的重叠BUG),这个光速限制就有可能是会被打破的,这也体现了一种很容易理解的程序思维:下层逻辑必须服从上层逻辑的约束。
怎样,作为一个普通观众,我们不仅又理解了一个现在最最前沿的科学难题,而且还获得了一种全新看待宇宙规律的视角,有没有一种成就感?
============================
【第七次追更】
为了庆祝点赞过5万,我们再追更一集吧。
这一集我们谈点什么呢?我们来谈谈量子纠缠问题吧,这个问题最近提到很多,也有朋友问到怎么用游戏的视角来解读量子纠缠问题,那我们这一更就聊下我们作为玩家如何理解量子纠缠。
开始前,我们了解一些基础知识先。
所谓量子纠缠,其实就是指微观世界里面发生的一种特殊的多粒子的耦合行为。通俗来说,就是几个粒子联成了一个整体系统了。不过它们联成的不是一个整体,而是一个整体系统,也就是说每个粒子还是单独存在的,而且可以分开,但是从关系上呢,它们之间又存在某种不可分割的整体关联。
一旦粒子之间有了这种纠缠关系之后,这些彼此纠缠的粒子不管身在何方,它们之间都能瞬间互相影响,而且这种影响不随距离的改变而消失,而且彼此之间的影响似乎也没有任何速度上的限制。
比如说,一对相互形成纠缠的粒子(我们把它们比作一对兄弟吧),我们把这对兄弟粒子彼此分开,然后让它们向相反方向飞去,并让它们尽可能的飞的相距更远一些,比如让它们相距百万甚至千万公里以上。然后,这时候我们观测其中一个哥哥粒子的某些属性,比如观测它的自旋方向。一旦当我们观测到这个哥哥粒子的自旋方向后,另一个弟弟粒子就能同时就能感应到它的兄弟被观测了,于是它马上也就显示出一个跟它哥哥完全相反的自旋方向来,以保持他们彼此绝对互补。
你瞅瞅这个过程,是不是会感觉其实并没有那么复杂难懂。也许这对粒子在分开时候自旋方向本来就是相反的,它们只不过保持了角动量守恒嘛,所以不管跑多远,你看了其中一只,自然就知道另一只的方向了啊。就像两只鞋子,本来就是一对,不管你把它们分开多远,你只要看到一只是左脚的,自然马上知道另一只就是右脚的嘛,这难道有什么奇怪的地方吗?
问题自然没有那么简单,科学家们自然也不会没想到。他们当然知道这种可能性,但是他们深入的研究了这个问题后发现,纠缠粒子之间的关系并没有角动量守恒这么单纯,它们有着更深入的互补性。
科学家们发现,两个粒子如果自旋方向简单相反的状态和两个粒子纠缠伴随观测变成绝对自旋互补状态,两者之间其实从数学角度来比较是不太相同的。这两种互补模式在数学上能发现一些细微的差别,而这个差别被一名北爱尔兰物理学家J·贝尔给抓住了,他提出了一个著名的贝尔不等式,用一个数学不等式清晰的显示出了两种自旋模式之间的数学差别。经典状态下粒子的自旋模式是符合这个不等式的,而量子理论里粒子自旋会突破这个不等式的约束。
这一段虽然我们尽量没引用太多物理或者数学公式(唯一只是展示了一下贝尔不等式的样子),但也是不太容易理解的,因此我们还是转换到虚拟世界的视角来重新讲述一下吧。
我们又来到我们创造的“量子世界”游戏中。
话说在游戏里,系统生成了一对宝箱。在每对宝箱里面有一只漂亮的蝴蝶精灵。而且我们已知,宝箱里面的蝴蝶精灵的颜色只有白色和黑色,每对宝箱里的蝴蝶颜色则一定是相反的,它们是一对“双子”精灵。那么毫无疑问,如果有一对宝箱,那么无论什么时候我们打开其中一只宝箱看到了里面的蝴蝶的颜色的话,就能马上知道另一只宝箱的蝴蝶颜色。
但是这个游戏的设计师告诉我们,这种成对宝箱的程序实现方式其实有些区别的。具体说就是成对宝箱其实有两种实现方式,一种是事先就生成好了一对双子蝴蝶,然后再分别装在不同宝箱里。这种先有蝴蝶再装进宝箱的方式我们命名为“传统宝箱”。而另一种呢,则是在你打开成对宝箱中的任意一只的一瞬间,才马上执行生成蝴蝶的代码,在两只箱子里立刻生成一对颜色相反的双子蝴蝶,我们将这种宝箱命名为“量子宝箱”。
于是游戏的设计师想挑战我们,想让我们试试看,能不能通过观察分辨出哪一对宝箱是传统宝箱,哪一对是量子宝箱。
这个挑战看起来似乎不可能完成,因为简单从开箱后的观察结果来看,似乎两种形式的宝箱都是完全一样的,两种都是装着颜色相反的双子蝴蝶而已,我们似乎无法分辨两者有什么不同。
但是,我们玩家都是很有耐心的,经过认真的反复摆弄两种不同的宝箱,重复开箱过无数次以后,我们还是发现了一些差别。我们发现,虽然每组宝箱里面的蝴蝶颜色都是相反的,但是对于量子宝箱来说,这两只蝴蝶的行为似乎更加对称一些,比如刚开箱的一瞬间,两只量子宝箱里飞出的蝴蝶连飞行方向也是完全相反的,甚至每只蝴蝶精灵其他的行为也都是完全相反的。而传统宝箱则完全没有这种现象,传统宝箱里的蝴蝶除了颜色区别,其他则看不出有什么关联性。所以,我们感觉量子宝箱里面的蝴蝶精灵才是“真·双子”蝴蝶,而传统宝箱里面的则是“伪·双子”蝴蝶。
自此,我们就成功的分辨出了两类宝箱的差别,我们完全能够通过观察开箱后蝴蝶的行为或者其他一些属性来判断,这组宝箱究竟是量子宝箱还是传统宝箱。而且,我们还更进一步的发现,任何量子宝箱一旦打开过以后,这个宝箱就马上变成传统宝箱了,你就算把蝴蝶再装回去,这个宝箱也不会再变成量子宝箱。
其实这也很好理解,因为蝴蝶已经生成出来了嘛。量子宝箱里的蝴蝶之所有表现出那么优美的对称性,其实就是因为它们是刚刚被成对生成出来的,它们只有在生成的一瞬间才能展现出完美的对称感。等到后面,你再怎么摆布这些已经生成好的蝴蝶,也无法再获得那种对称感了。
而且我们用程序刷新出这对蝴蝶这个过程也是不可逆的,所以只要蝴蝶已经被程序生成出来后,它就不可能再变回成为一段代码,不能被再生成一次。那么,量子宝箱也就蜕变成了一个传统宝箱,永远也不可能再变回成原来的状态了。所以,量子宝箱其实是一种一次性的宝箱。
这个技巧很快就被大家用来判断某个量子宝箱是否被人打开过了,因为量子宝箱只要打开过一次,那么它就变成了传统宝箱,我们就可以用观察蝴蝶行为的方式判断出它已经不是量子宝箱了,它已经被人打开过了。大家还发现,量子宝箱的这种神奇的特性非常有趣,它几乎是无解的,没有任何人有办法把打开过的量子宝箱还原回去,就像我们不能把一段程序运行得到的结果再变回成一段程序一样。
那么量子宝箱的这个神奇的特性可以用来做什么呢?大家想到了什么没?
有人很快想到了,我们如果把一张写给别人的字条也同时放在量子宝箱里,那么不就可以防止别人偷看了么。因为,任何人想偷看量子宝箱里面的字条,就必须打开宝箱,但是只要量子宝箱被打开过了,那就无法还原回去了,这样收到宝箱的人通过判断宝箱是否被打开过从而知道里面的纸条是否被别人偷看过了。这样,量子宝箱可以成为一种游戏中绝对安全的“邮件封印”,就像古代的火漆封笺一样,一旦封上就可以保证里面信息的绝对无法在不破坏封印的前提下被别人看到。而且火漆可以有办法伪造,量子宝箱却绝对伪造不了(请记住,是理论意义上的绝对伪造不了)。
我们上面讲述的这个虚拟世界游戏的例子,其实就是对应着量子纠缠和由此发展而来的量子加密通讯技术的基本原理。
量子宝箱就是象征着处于纠缠态的量子对,传统宝箱则是普通的粒子对。开宝箱的过程其实就是我们的观测行为。所以,所谓量子加密,并不是一种无法解开的加密算法,而是利用纠缠量子来搭载传递信息的方法,这样传递可以一定程度保证信息的安全性,接受者能准确无误的知道自己是否是信息的第一个阅读者,而且不用担心有人偷看过之后又伪造了量子态来假装这个信息没有被阅读过。
所以量子加密通讯其实传递的还是经典信息,信息传递速度也并没有超越光速,也同样有可能被窃听,只是无法被不察觉的窃听而已。
量子加密的绝对安全性其实是来自于量子纠缠的状态被退相干后(就是观测后)是无法被人为复原的特性。处于纠缠态的量子对在被观测的时候,这一对粒子的状态才同时确定(你也可以说是同时生成),而且它们一切的状态一定都是相反互补的,这种互补性用传统的粒子对无论如何也模仿不出来的。这种差别也就是J·贝尔用数学描述出来的贝尔不等式所表达的含义。科学家为了验证这种互补性确实存在,已经做过了无数次的试验,他们把纠缠态的光子对分开几万公里,甚至在太空中找到分开更远的纠缠粒子,反复的测量它们的行为,每一次都证明了贝尔不等式是成立的。
这种现象放在现实里其实是非常令人难以理解的,因为两个纠缠粒子在物理距离上已经相隔千万里之外了,但是它们依然能保持超越时空的协调性,而且绝对不是简单的动量守恒能解释的,它们表现的就像完全没有被分开一样。这种令人费解的现象,就算强大如爱因斯坦也感到不可思议,甚至爱因斯坦的后半生时间都一直在和量子物理的这些现象斗争,他试图证明粒子之间不可能通过超越光速的速度传递信息(定域性),也不可能通过一只粒子的状态知晓另一只的状态(实在性)。结果很不幸,现实中的实验一次又一次的证明爱因斯坦是错的,
要知道,爱因斯坦当年创立出的伟大的相对论就是依靠着定域性和实在性才能成立,而相对论在宏观上同样也被证明是对的。物理学的两大著名理论彼此矛盾,但是居然都是对的,量子理论在微观领域被证明是对的,而相对论在宏观领域也被证明是对的。这令大家有没有想到什么?其实物理学上这一幕已经发生过了,就是所谓的“黑体辐射问题”,这个限于篇幅就不详细谈到了。
总之,在现实世界里面想要统一这两大理论是非常非常困难的,困难直到现在还没有任何人能做到。这也是物理科学现在最前沿的目标之一,也就是所谓的“大一统”理论。很多科学家认为,人类一旦掌握了大一统理论,那么整个物理学将进入一个新的境界,人类的科技水平也将随之产生飞跃式的进步。
不过在现实中人类最顶尖科学家也难以做到事情,在虚拟世界里,我们却可以放飞思维,大开脑洞,让我们普通人也能尝试理解人类顶尖智慧都无法解释的问题。
你看,如果是在虚拟世界里,量子纠缠的种种神秘现象也就不再稀奇了。在虚拟世界里,我们把所有的粒子在非观测状态都假设成为一段代码函数,而两个纠缠的量子其实就是重新编码在一起的同一个波函数而已,只不过区别就是这是一个“双子函数”,我们如果运行这个双子函数可以一下得到两个粒子的数值。如果是这样的话,纠缠态的两个量子为什么会如此同步就非常好解释了,因为它们本来就是同一个函数输出的两个互补的运算结果嘛。这种运算行为和距离无关,无论这两个粒子在物理距离上被分开多么遥远,它们在本质上还是属于同一个波函数,只有当我们观测其中一只的时候,这个波函数就瞬间被执行并输出了一对结果到两只粒子上。所以,另一只的状态马上就得到确定了,而且两只粒子的状态一定是绝对,完全互补的,因为它们都是刚刚从同一个波函数里生成出来的,也这种刚刚刷新的互补状态才能突破贝尔不等式的数学约束。
所以,突破贝尔不等式实际上正好证明了这两个粒子是在观测时候刚刚同时产生的,而不是事先就存在的。因为事先就有的两个粒子无法在经过长途传输之后还能保持如此一致的协调性,也无法突破贝尔不等式的约束。
爱因斯坦说,如果量子物理是自洽的,那么世界的定域性和实在性我们必须放弃一个。而爱因斯坦一直都坚持两者都不肯放弃,因为他的相对论就是依靠两者而成立的。所以他只能转头试图证明量子物理本身是不自洽的,他提出了一个又一个的佯谬企图推翻量子理论,可惜他并没有成功,他所提出的那些佯谬后来反而都成为了反证,令的量子物理的基础越来越坚实,而这也成为了爱因斯坦晚年一直未能释怀的问题。
那么我们如何看待虚拟世界里的定域性和实在性呢?
如果从虚拟世界的角度来分析的话,这种虚拟世界背后的程序关联性才是纠缠粒子之间的神秘协调性的根本来源。那么,这定域吗,似乎虚拟世界还是保持了定域性的,因为信息的传递并没有超越光速,波函数的坍缩并不算传递信息。那么,这实在吗?这似乎受到了挑战,我们能说一段代码在被执行前,它的输出结果就存在吗?这就像询问玩家,在你进入地图前BOSS存在吗一样。玩家必须回答说不知道,也就是说粒子在被观测前其具体属性是不实在的,只有概率可能。
所以,我们采用虚拟世界的视角解读世界的时候,实际上就是放弃掉了物质世界的实在性,而坚持世界是定域的。我们这个虚拟世界里面规定了,任何信息的传输速度不会超越光速,光锥之外物体之间绝对不能互相影响,但是这些物体并不实在,它们的本质都是代码,而不是结果,你不观测它们的时候,它们的属性都不客观存在,所以也只有这种不客观的属性才让纠缠量子之间能有看不见的底层联系来协调彼此的属性,所以它们才能超距关联但又不破坏定域性。
你看,我们对我们所构建出来的虚拟世界的认知又进了一步,我们现在知道我们的虚拟世界是定域但不实在的,我们放弃了实在性但是维护了实定域性以保证宇宙最大光速的可靠,但我们又用代码态来解释量子态,以解决纠缠量子远距属性协调的问题,所以相对论依然还是成立的,量子物理也同样是成立的,它们在我们虚拟世界的游戏里终于成功化解了矛盾。
我们,大一统了(忍不住得意的笑起来)。
=========================================
【第八次追更】
各位知友太捧场了,点赞都过6万了,那么我再回馈一章吧。
这章咱们聊点啥呢,我听有同学说搞不明白量子计算到底是咋回事,为什么量子计算就能解决传统计算机解决不了的问题,量子计算机有那么神奇吗。
那我们这更就来谈谈量子计算是咋回事吧。
那么,我们从哪里开始呢?
还是要从我们最早讲的那个最简单的实验:“双缝干涉”讲起吧。这个实验虽然简单,但是其中蕴含的知识真的是相当丰富,那让我们再解读看看还能发现什么。
在双缝干涉实验中,我们已经用程序员的视角做过了通俗解读,我们再简单回顾一下:
当一个单光子从光源被发射出来后,就变成了系统中虚无的概率波函数。然后系统开始根据概率波的扩散速度(光速)监控概率波传播路径上一切即将发生的观测事件,当观测事件即将发生之时,系统就会瞬间结算概率波经过的空间和路径上的所有传播情况,在观测位置汇总波函数然后进行坍缩,最后得到一个光子的具体测量结果,如果是光屏则得到了一个屏上的光点。当然我们也可以测量光子的其他属性,比如偏振角,速度或者能量等等,总之,你想知道什么就测量什么好了,系统会从波函数中立即计算并呈现给你。
等等,大家发现什么没有?
我在这段描述里面使用了计算这个词:”系统会从波函数中立即计算并呈现给你“。我们这更正好要讲量子计算,这里就出现了计算,大家觉得是不是有点关联呢?
可能大家要想,这也能算计算吗?这不就是波函数的自然坍缩么?这里面看不出和我们所理解的计算有什么关联啊。
当然有关联,大家试想一下,如果我们把光线传播的距离拉长到比较遥远的天文尺度上,那么当波函数穿越了漫长的空间距离,飞跃几百上千万光年,途中还要经历星云遮挡,引力透镜,多普勒效应等等各种影响,最后才能到达我们观测它的位置。但是,在延迟选择实验那章我们就知道,波函数在被观测的最后一刻,它瞬间就会坍缩变成光子,而这个光子里所蕴含的特性里就自然包括了这漫长传播路径上的各种各样的事件的概率影响。
这个坍缩的过程其实已经包含了两个进行计算的最重要的特征,一个是存储,波函数能无尽的叠加路径上的各种可能概率事件,这本质就是存储了大量信息。第二则是运算,从复杂的概率组合里瞬间完成了坍缩结算,这就是运算能力。
如果说,宇宙是一台计算机模拟出来的世界,那这台计算主机的算力一定是我们所想象不到的强大,强大到我们都看不出光子在实验室里传播几十厘米和在宇宙中传播千万甚至亿万光年在最后坍缩计算的一瞬间有任何时间上的差别,光子的坍缩瞬间,波函数的计算似乎是不需要时间的,哪怕其中蕴含的计算量无比惊人的庞大。
那么,就有一些科学家开始琢磨了,如果真的说我们的宇宙背后有这么强大的算力在支撑,那我们能借来用用么?
可是,这个想法真的很诱人啊,你想想,造物主用的设备,那得是天神级的吧。
啧啧,这能用一下感觉要逆天啊。
那就用一下吧,既然造物主没说不能用,干嘛不试试呢。
于是科学家就打起了量子的主意,科学家们琢磨了一下,如果要发挥量子的计算能力,那就要用好量子的几个特性:
一个是“叠加态”,量子可以把各种可能性都叠加到一起,但是呢又不完成计算,就这么叠着,这感觉有点意思啊。
为什么呢?大家想想看,如果我们用传统计算机要计算两个未知范围的随机函数的值相乘的结果,那得怎么算,先得不断的跑循环让两个随机函数输出结果,分别记录两个结果的集合,等到已经充分反映出随机函数的结果分布情况后,再把两个集合做张量积的运算,最后得到的集合才能说是两个函数乘积集合的取样集合。
如果我们要多算几步类似的运算的话,那再牛的计算机也受不了了。先不说运算时间,光是存储这些中间数值需要的内存容量都是不断指数上升的。
所以,如果是量子计算机的话,我们就可以把代表两个函数的量子比特给乘法叠加起来,成为一个新的量子比特,只要我们不测量它,这个新的量子比特也不会多占空间,但是它又已经代表了计算结果,如果我们还要继续计算,那也可以继续再叠加其他的量子数值。
总之,等最后算完,我再测量就好,这就像光子穿越了无数时空,最后在光屏上坍缩也就一瞬间一样,并不需要任何计算时间就完成了。
量子的另一个特性就是“纠缠态”,之前在我们谈到量子纠缠的时候就说过不同的量子可以彼此纠缠,形成一个共同的整体。
这个纠缠态在量子计算机里面,就是计算关系了,比如我们能用纠缠的方式让两个量子比特相加,或者做某种逻辑运算,于是两个量子比特就能通过关系纠缠成为一个整体,同时完成了一个量子态和量子态之间的计算,这种计算本质就是概率的彼此叠加,相当于传统计算机是用上一步的计算结果来运算下一步,而量子计算机是直接把代码拆散重新编程并打包成新的函数了。
听起来是不是还是有点晕?
没关系,我们还是换成虚拟世界的视角再来了解一下吧。
假设在虚拟世界的游戏里,我们有一个宝箱需要用正确的密码打开,而密码的输入是用十个10面的骰子,骰子的十面上分别刻着0-9的数字,然后要把正确的号码向上朝前放到宝箱的十个小孔里面才能开启宝箱。
假如我们并不知道宝箱的开启密码,那么我们就需要尝试100亿次才能穷举完所有的组合,假设我们尝试到50%的时候能试出密码,那么也需要尝试50亿次,假设我们动作敏捷,每秒就能尝试一次,那么大概我们花158再加半年的样子就可以成功了,这真是几代人都无法完成的宏大工程。
那么,怎么办呢,我们决定不要用经典的骰子来尝试了,我们换成能随机生成0-9的骰子函数,也就是量子骰子来尝试。
我们先制造10个量子骰子,每个骰子都能平均表示0-9的叠加态,我们把这10个量子骰子全都塞入到宝箱的密码口里。现在宝箱也被量子骰子给影响了,它也变成了不确定的状态,10个量子骰子能把宝箱变成什么样的叠加态呢?自然是变成两种状态的叠加态,一种是开启,一种是关闭。
为什么宝箱会有开启的状态叠加进去?
因为10种骰子的全排列组合里必定有一种的正确的组合是可以打开宝箱的啊,而10个量子骰子组合就代表了全部100亿种的密码组合可能,那么量子骰子的叠加态里面就一定包含有那个正确的组合,我们再用骰子去和宝箱叠加,所以得到的宝箱叠加态里面也就一定有百亿分之一的状态是被成功打开的。
到这里,大家应该还觉得似乎还算说得通是吧,接下来,请大家深吸一口气,因为我们要开始进行骚操作了。
我们现在用一种量子比较器,将那个宝箱开启状态的微弱可能性给选择出来(实际是翻转其概率)。这实际上是可以做到的,我们能在无数的叠加态中把我们希望找到的那种状态用量子电路给选择出来。
好了,我们知道这肯定是极小极小的概率,只有百亿分之一,但是不重要,只要存在我们就能给它选择出来。
然后我们用一种量子放大器来放大这个开启状态的几率,反复的千百遍乃至几十万遍的放大,直到这个几率接近100%为止。
好了,我们的最后一步就是测量这个被我们篡改过状态的量子宝箱。
按照我们之前的了解,我们知道这时候宝箱会立即坍缩。因为我们之前已经把宝箱开启状态的可能性给大大放大了,所以现在坍缩的宝箱接近100%的可能性就是开启的,那么宝箱有极大可能就是坍缩成开启状态(如果不是就再来一遍好了)。
当然,我们的目的不是得到这个坍缩的宝箱,我们知道量子宝箱如果一坍缩的话,宝箱里面的10个量子骰子也自然会跟着一起坍缩。如果宝箱坍缩成了开启状态,那么10个量子骰子也就只能坍缩成为能开启宝箱的的密码组合,因为它们之间的逻辑关联必须被符合。然后,我们只要去看看坍缩后的骰子状态就轻松得到了那个用传统方法要尝试几代人的正确密码!
是不是很惊喜,是不是很意外?有没有觉得不真实,感觉就像是你考试的时候偷看了标准答案一样。
是啊,我们几乎什么都没尝试,就让这些量子们自动帮我们“选”出了唯一正确的答案,而这个神奇的操作居然能让我们实实在在的节省了一千多年的常规计算时间,我们也不用等十几代人才知道结果了,这真的可以算的上神迹了!
可能大家还有点蒙是吧,这是正常的,这是典型的量子眩晕症状。任何第一次听说这种奇怪逻辑的朋友都有可能出现这种眩晕症状,但是不要怕,我们要学会享受这种量子微醺状态,这是普通人接触到神迹后的一些正常反应而已,我们习惯就好了。
不过为了缓解大家的这种症状,我再尝试用比较通俗的语言把量子计算的过程分步解释一遍。
第一步,我们首先用若干量子比特模拟了十只骰子的全部组合排列,获得了一组代表100亿种可能性的量子骰子;
第二步,我们接着用这组量子骰子输入到加密宝箱,就得到了“”输入全部骰子组合后的全部宝箱的组合”,这个全部宝箱的组合就相当于我们把100亿种的骰子密码全部输入后得到的100亿种宝箱的状态的集合。而这个集合很显然是由1种开启状态和99亿9999万9999种关闭状态组合在一起的,而且这100亿种状态的概率目前全部都是相同的(都是100亿分之一);
第三步,我们用量子比较器把宝箱组合里面唯一的那种开启状态先选择出来,再用放大器把这个特定状态的概率翻转后再不断放大(相当于同时降低其他关闭状态的概率)。如果我们将这个开启概率放大到99.9%,其实就是相当于我们把叠加后的结果人为给扭曲成了99.9%的概率是开启状态;
第四步,我们用测量的方式去坍缩这个被我们扭曲了概率的结果,从而带动模拟十个骰子的量子比特也一起坍缩。因为结果已经被扭曲成大概率是开启状态了,那么量子比特坍缩出的结果也大概率就是正确的开启密码组合,如果运气不好还不是的话,那么就把上面步骤多来几遍好了。
你看,我们分四步就把大象装进了冰箱,就说神不神奇。
大家可能会怀疑,难道量子计算的操作这么节省时间吗,用那个什么比较器还有放大器操作的话,难道不需要很多计算时间吗?
我们就姑且认为现在量子计算中的这些操作要比我们经典计算机里面的传统运算操作的单位速度要慢一些吧,不过这种慢只是单一指令上的慢,而量子计算带来的快却是计算量在数量级上的减少带来的快。
你认真试想一下我们刚才寻找宝箱密码的整个计算过程,量子计算和经典计算相比,在第一步就出现了绝对的优势,量子计算一次就拿出了10个处于叠加态的量子10面骰子(当然具体计算的时候肯定是用量子比特来编码模拟10面骰),这相当于传统计算机的什么概念,相当于传统计算机10^10=100亿个普通的数据。
如果我们要用传统计算方式的话,肯定要用10×10的循环结构来遍历这个10个骰子的组合数字,逐一尝试,但是就算我们能飞速的跑这个循环,再快也只能是以线性串行的方式进行比较。而量子计算机就不同了,它可以将10个量子骰子的全部组合一次性输入宝箱并尝试完毕,这就相当于做了把100亿次的比较用一次并行操作给完成了,剩下的当然就是把操作以后的结果拿来慢慢挑出正确结果了,而结果只有两种:关闭和开启,在两种结果里选一显然比在100亿种组合里找一要容易的多。
所以,过程中量子的各种操作不管怎样慢,那也比用传统方式进行100亿次串行式的逐一比较要快太多了。
事实上,量子计算机的确也还要做不少次的计算操作,比如需要把那个极小极小的开启状态的概率给放大很多倍,但是这个操作次数也远远小于逐次比较。科学家已经证明了,如果我们用传统计算机来逐一比较的话,N个数平均需要比较N/2次,这很好理解,至少平均要比较一半嘛,但是用量子计算机呢,我们只需要做 � 次放大操作就够了,显然 � 是远远小于N/2的,而且N越大,我们要查找的信息量越大,那么量子计算机的优势就越明显,而这就是所谓的量子计算的优越性。
在这整个过程中,可能大家最好奇的就是我们怎样制作出量子骰子呢?我们要怎样才能用电子设备模拟出一个“没有扔出的骰子”来呢,或者说模拟出一个具有量子特性的计算元素呢?
其实,这也很简单,想要让计算元素有量子的特性,最简单的办法就是用量子本身来当作电路元件就好了,我们去找一个量子来(当然不是去抓一个野生量子,野生的不好养活,这个还是要在人工环境里制备出来的),然后放到计算机里当作基础元件,这个元件的名字就叫做“量子比特”。
现在制备量子比特元件的方案有很多,比如光量子,超导,离子阱,中性原子等等,总之就是用某种技术把一个可操作的量子态粒子给固定到计算元件里,然后就成为了可用的量子比特。
当然具体讲要量子计算机的硬件方案,那写三天三夜也写不完了,我们也不需要了解的这么专业,反正这些方案现在都还不成熟,距离真正实用还远着呢,我们这些普通群众用不着太过积极了,先等科学家们搞出真正可以实用的设备再说。
好了,我们拼尽全力,尽量通俗的解释了一下量子计算的基本原理,当然还有同学问,那么这个放到游戏视角是个什么行为呢?
来围观一下MC里牛x玩家制造的红石计算机的行为,玩家完全用游戏元素搭建的集成电路,包括CPU,内存,显示芯片,I/O系统等等,还有屏幕,并且可以正常运行。
这种设备在游戏里面怎么能运行起来?它的算力从哪里来的?
你猜!
好了,本更就先讲到这里,当然如果还有更多兴趣的同学欢迎去观看本回答的延伸会员专栏,欢迎会员订阅。
上帝是个程序员:游戏制作人眼中的量子物理www.zhihu.com/xen/market/remix/paid_column/1517196714129252353?entry=qa
Q:新组装的台式机偶尔会自动重启,不固定时间发生,发生频率也不高,,有时候开机几分钟就突然重启,有时候玩半天突然重启,有时候挂一夜好好的。
A:最终发现是小米插排(带 1USB + 1TypeC那款)的问题,换成公牛插座即刻解决,原因不清楚,可能是小米这款插排供电不稳定吧。