V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  lesismal  ›  全部回复第 62 页 / 共 70 页
回复总数  1384
1 ... 54  55  56  57  58  59  60  61  62  63 ... 70  
2021-06-04 00:15:43 +08:00
回复了 redbelt 创建的主题 Java 推荐周志明大大的一片文章《云原生时代, Java 的危与机》
周神好帖!
越读书越觉得自己会的少,学得越多越觉得自己无力。
但愿楼上随便喷周神观点的各位有朝一日都能具备真正俯视其内容的实力。
2021-06-01 15:38:31 +08:00
回复了 ffw5b7 创建的主题 MySQL 求助:sql 优化。
生气那是开玩笑呢,v 站 emoji 不显示 :joy: 不知道怎么破,好像是可以输入表情来着,忘记怎么搞了

再补充点吧:如果你的数据是只有几十万甚至几百万这种量级,直接内存做也可以,这点内存不值钱。比如启动时初始化,分批查出每条数据按照你需要的关键字生成一条 string,存到 trie tree 里,查询时按关键字最多到最少循环查询,大于等于 limit 数量时结束循环。如果数据需要动态更新,更新 tree 成本也很低。
甚至,就内存里按关键字弄几个排好序的,二分查找就是了,除了 go 这种,其他很多语言本身就自带这些有序的 container,没啥成本

如果数据量是持续增长的,目前的数据量,改造成本也不大,早治疗早解决。
2021-06-01 13:59:02 +08:00
回复了 ffw5b7 创建的主题 MySQL 求助:sql 优化。
1. #4 中描述只有几十万数据,是固定的地址数据吧?这里没有给出详细信息
2. 问的问题是 sql,#6 中说改造 es 是指什么?到底用的 sql 还是 es,我的回答里好像没说需要改造成 es 。另外,但就这个查询来讲,sql 和 es 都适用
3. 这个接口功能是地理位置推荐

综合下:数据数量几十万、地理位置推荐,那我排除是按收件人地址类的搜索,假定你的数据量数量固定为几十万。

如果是按照位置范围内远近进行推荐,mongodb 有地理位置存储和查询的支持,可以考虑数据导入到 mongo,导入时把地址的经纬度信息带上,然后再做,就简单了,而且比你用字符串可能更准确
如果不需要按位置远近这种,只需要简单优化 sql 性能,#5 几种姿势说的很明白了,并且你才几十万数据,这么点数据量改造成本太低了。我怀疑楼主要么没看我的回答要么就是懒,然后还继续问什么奇技淫巧,那老夫我现在有点生气,不想再回答了 :joy:
2021-06-01 12:23:45 +08:00
回复了 ffw5b7 创建的主题 MySQL 求助:sql 优化。
一,插入数据前对 detail_site 进行标准化,比如广东深圳、广东省深圳市、中国广东省深圳市之类的,省市格式统一标准化成中国-省-市,然后直接 detail_site order by,不需要函数,需要修复旧数据
二,需求降级,问问产品,能不能不 order by 这么细,就按 detail_site 字符串排序,如果可以,就不需要用函数了
三,新增整形字段作为省、市排序值,更新当前所有记录的该字段值,后续插入时带上该字段值,查询用这两个值 order by

ps:单一手段不可行的情况下,就要从不同的层次、角度考虑,穷则思变,不要局限在 sql 本身上
2021-05-29 14:20:50 +08:00
回复了 xuegy 创建的主题 生活 室友一边洗澡一边炉子上开火做饭,屡教不改,如何劝导?
合同是你签的,建议多拍几个她煮着东西的时候洗澡、包括你提醒她的视频,以后万一你不在家她把房子烧了也好有个证据
2021-05-26 17:25:52 +08:00
回复了 AkideLiu 创建的主题 程序员 C++ 关于 recursion 的一个小问题
简单直接的判断方法:
3 为临界值,n=3 时最多向下 n-1/n-2/n-3,即 recur 最小的参数 n 为 0 ;
每个 n 对应的值都进行记忆的前提下,每个 n 只需要调用一次 recur ;
首次调用 recur(6),则整个过程需要对 0-6 挨个计算、记忆,所以是 7 次(不管小于 3 的参数是否记忆,当 n=3/4/5 时 n 也被缓存过、不会被重复调用,所以小于 3 的也不会被重复调用)。
可以类推首次调用大于等于 3 和小于 3 的次数
2021-05-25 12:04:26 +08:00
回复了 longway 创建的主题 git 真有人觉得 Git 会提高生产力?
“Go 和 javascript 速度居然差不多。”
—— 这个没关系,毕竟 js 逻辑单线程,对多核心的利用能力肯定是不如 go 的,有人可能说 js 可以开多进程,但是 go 相比多进程还有内存共享、无需通信的优势,在面对更复杂业务功能时还是要强于 js 。所以单就服务端领域,抛开什么社区轮子或者说用 node 弱全栈配合写前端的优势,纯做服务器,go 还是比 js 强大太多,否则 node 爹当年也不会在熟悉了 go 之后感慨 node 不适合做服务器、而是适合辅助前端开发
“Java 比 Go 快,而且领先幅度不小。”
—— 这是错觉。

全部对比应该是在这里吧:
https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/go.html

这是 go 和 java 对比的,大部分测试项 cpu 消耗其实各有千秋,最后两个测试项差距确实很大,但是,稍微修改下再对比:

以最后一项的 binary-trees 为例( go 耗时 12.80s ,java 耗时 2.48s ):

go 代码修改:
func inner(depth, iterations uint32) string {
chk := uint32(0)
tree := bottomUpTree(depth) // 这里从循环内移到了循环外
for i := uint32(0); i < iterations; i++ {
chk += itemCheck(tree)
}
return fmt.Sprintf("%d\t trees of depth %d\t check: %d",
iterations, depth, chk)
}

java 代码修改:
for (int d = MIN_DEPTH; d <= maxDepth; d += 2) {
final int depth = d;
EXECUTOR_SERVICE.execute(() -> {
int check = 0;

final int iterations = 1 << (maxDepth - depth + MIN_DEPTH);
final TreeNode treeNode1 = bottomUpTree(depth); // 这里从循环内移到了循环外
for (int i = 1; i <= iterations; ++i) {
check += treeNode1.itemCheck();
}
results[(depth - MIN_DEPTH) / 2] =
iterations + "\t trees of depth " + depth + "\t check: " + check;
});
}

我对 java 不熟,猜测 java 的编译器对 for 循环内局部对象甚至 tree 的构造过程做了复用优化

因为这种简单逻辑内的遍历,更成熟的老龄编译器可能会做更针对的优化,C++比 C 性能强主要就在于现代 C++编译器的优化,并且实际的业务场景,很少有需要这种频繁创建这样深度和节点数量的临时对象,几乎不会遇到这种小代码段级别的优化在实际业务中发挥太大性能优势,所以把遍历的部分构造放在外层时只对比 check 消耗时,性能差不多、在我机器上 go 略好。

语言、编译器有一个漫长的成长阶段,go 会越来越强的
2021-05-14 20:04:27 +08:00
回复了 ng29 创建的主题 Go 编程语言 资讯一个 golang 并发的问题
@baiyi 你的钻研精神非常棒,很赞,继续加油!
2021-05-14 16:22:01 +08:00
回复了 ng29 创建的主题 Go 编程语言 资讯一个 golang 并发的问题
@baiyi 放松一下,出门转转透透气,喝点茶水、咖啡,眺望下远方,过阵子再想,就豁然开朗了。有时候思考比较绕的问题会懵住,我也经常,有时候要一个问题纠结几天想不明白,然后放下了,突然某个时候又想起来、灵光一闪,灯火阑珊的感觉
2021-05-14 16:19:26 +08:00
回复了 ng29 创建的主题 Go 编程语言 资讯一个 golang 并发的问题
@baiyi 你相当于是用可能性去解释必然性,所以会懵 :joy: :joy:
2021-05-14 16:15:46 +08:00
回复了 ng29 创建的主题 Go 编程语言 资讯一个 golang 并发的问题
@baiyi 其实就两点:
1. #20 里的 [3->4->1] 与 [2->5->6],这两段不包含 chan 的过程互相没影响的两个并发流,所以,跟 chan 没关系
2. 抢占式,随时可能被调度,跟是不是 print 也没关系

chan 和 print 都不是影响实际运行时的调度的充要条件,如果你多加一些 print,除了各自 goroutine 内的顺序能保证,多个 goroutine 之间的顺序没法保证
chan 、print 或者其他语句,是被调度器决定他们的执行权,他们反过来只能影响调度器对调度时间等的累计、调度时间的分配,但只是影响,影响是“可能会怎样”而不是“必然会怎样”
2021-05-14 15:27:42 +08:00
回复了 ng29 创建的主题 Go 编程语言 资讯一个 golang 并发的问题
@baiyi 所以我让你看调度的资料,#12 就说过了:
“—— golang 好像是 1.2 版中开始引入比较初级的抢占式调度,然后好像是 1.14 做得更彻底,即使 for{} 也能释放调度权了”

“所以我们的结论并不是矛盾的”
—— 想啥呢,你的解释跟实际现象都不一样了。。先去查资料,去分析为什么会这样、不要纠结于自己分析的对错,纠结对错就被自己陷住了、会不自觉地想往自己是合理的方向上靠、然后失去理智分析的判断力
2021-05-14 15:12:14 +08:00
回复了 ng29 创建的主题 Go 编程语言 资讯一个 golang 并发的问题
@baiyi
“不过去掉偶尔存在的乱序问题,连续两次的输出可以认为是 chan 等待队列机制的作用吗?”
—— 你搜下 golang 内存模型、happens before,结合 #20 的例子,其实楼主这个例子是对 chan 在要求时序场景用法的误解,[保证内存读写顺序 /临界区顺序] 跟 [多个并发流非锁定(包括类似#20 用 chan 做类似的穿行方式)区域内代码段调度顺序] 是两码事。
如果想明白了,你就能理解其实这个现象跟 chan 没直接关系,你只要思考代码段、调度就行了:楼主代码里的 chan send 和 recv 后面直到下次循环 send recv 阻塞之前的代码段,其实都是无串行化的两个或者多个并发流,这些代码段(相当于#20 里的 [3->4->1] 与 [2->5->6],这两个过程中互相没影响没有被串行化),并不受 chan 内部实现逻辑的影响,而是被调度器决定运行时机

上一楼怕有误解,编辑下,v 站这个不能编辑确实难受 :joy:
2021-05-14 15:08:01 +08:00
回复了 ng29 创建的主题 Go 编程语言 资讯一个 golang 并发的问题
@baiyi
“不过去掉偶尔存在的乱序问题,连续两次的输出可以认为是 chan 等待队列机制的作用吗?”
—— 你搜下 golang 内存模型、happens before,结合 #20 的例子,其实这个是对 chan 在要求时序场景用法的误解,保证内存读写顺序 /临界区顺序,跟多个并发流非锁定(包括类似#20 用 chan 做类似的穿行方式)区域内代码段调度顺序是两码事。
如果想明白了,你就能理解其实这个现象跟 chan 没直接关系,你只要思考代码段、调度就行了:楼主代码里的 chan send 和 recv 后面直到下次循环 chan recv 阻塞之前的代码段,其实都是无串行化的两个或者多个并发流,这些代码段(相当于#20 里的 [3->4->1] 与 [2->5->6],这两个过程中互相没影响没有被串行化),并不受 chan 内部实现逻辑的影响,而是被调度器决定运行时机
2021-05-14 15:01:34 +08:00
回复了 ng29 创建的主题 Go 编程语言 资讯一个 golang 并发的问题
@baiyi 咱们再看下 print 的源码

```golang
package main

func main() {
print("hello world")
}
```

print 是 buildin,对应的汇编源码:

```sh
go tool compile -S .\print.go > print.s
```

有点长,只看 print 的部分:

```asm
0x0024 00036 (.\print.go:4) CALL runtime.printlock(SB) // 加锁
0x0029 00041 (.\print.go:4) LEAQ go.string."hello world %d, %s\n"(SB), AX
0x0030 00048 (.\print.go:4) MOVQ AX, (SP)
0x0034 00052 (.\print.go:4) MOVQ $19, 8(SP)
0x003d 00061 (.\print.go:4) NOP
0x0040 00064 (.\print.go:4) CALL runtime.printstring(SB)
0x0045 00069 (.\print.go:4) MOVQ $1, (SP)
0x004d 00077 (.\print.go:4) CALL runtime.printint(SB)
0x0052 00082 (.\print.go:4) LEAQ go.string."hi"(SB), AX
0x0059 00089 (.\print.go:4) MOVQ AX, (SP)
0x005d 00093 (.\print.go:4) MOVQ $2, 8(SP)
0x0066 00102 (.\print.go:4) CALL runtime.printstring(SB)
0x006b 00107 (.\print.go:4) CALL runtime.printunlock(SB) // 解锁
```

print 执行过程中是对本 m 加了锁的,即使是 runtime.GOMAXPROCS(1),也能保证 print 先后的顺序:
https://github.com/golang/go/blob/master/src/runtime/print.go#L66
https://github.com/golang/go/blob/master/src/runtime/print.go#L76

而即使加了锁,依然会出现非固定的两两一组或者交替,说明这并不是进入 print 后造成的,所以即使是源码分析,也跟直接 print 还是 fmt 的 print 系列没关系
我前面说的 print,都是说 print 之前就可能被调度了,其实都是调度器决定的,而调度器并不能保证这些固定的顺序
2021-05-14 14:25:06 +08:00
回复了 ng29 创建的主题 Go 编程语言 资讯一个 golang 并发的问题
@baiyi 两个问题:

1. 分析楼主的问题,当然应该尽量用楼主相同的代码好些 :smile: :smile:

2. 你这里的例子循环次数只有 5,数量太少可能观察不到,修改下就来 10 秒的,你试试这个
package main

import (
"runtime"
"time"
)

func main() {
runtime.GOMAXPROCS(1)
ch := make(chan int)
go func() {
runtime.Gosched()
for i := 0; true; i++ {
ch <- 100
print("written", i, "\n")
}
}()
var ep = 100
go func() {
for {
ep = <-ch
print("received\n")
}
}()
time.Sleep(10 * time.Second)
}

然后再统计下( print 好像是直接 stderr 的,所以重定向下):
go run main.go 2>&1 | uniq -c | awk '$1!="2"'
或者 > x.log 日志文件你自己再搜下,应该就可以发现有不是连续两次的,我这里已经有只一次的日志产生
2021-05-14 13:15:54 +08:00
回复了 ng29 创建的主题 Go 编程语言 资讯一个 golang 并发的问题
@baiyi 一起学习研究,有新发现咱们继续讨论
1 ... 54  55  56  57  58  59  60  61  62  63 ... 70  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1334 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 28ms · UTC 23:47 · PVG 07:47 · LAX 16:47 · JFK 19:47
Developed with CodeLauncher
♥ Do have faith in what you're doing.