最新要闻
- 大连地铁敞门行驶 线路刚开12天:客服称“原因正在调查”
- 快资讯丨00后女生毕业当猪场保育员:她认为这行业很有潜力
- 世界快资讯丨微软反戈一击 反垄断战火引至日本本土
- 当前头条:东南亚出游降温:机票降幅达40%
- 【天天快播报】促消费,振内需,康佳加速业务高质量发展
- 世界第一名宇航员!尤里·加加林坠机遇难地点照片首次公开
- 每日看点!真的可以免费坐高铁了!用12306积分兑换:官方教程收好
- 焦点速递!杭州地铁现打工人专线 网友:通勤都不让闲着
- 环球观察:《指环王:力量之戒》片场马匹死亡 动保组织谴责:剥削动物
- 魅族20系列大杯曝光:120Hz E6直屏、12GB+512GB组合
- 核磁共振增强剂的危害_核磁共振增强剂的危害
- 环球热文:高德、阿里云发布全新车路协同方案 夜间开车像开了上帝视角
- 世界热文:瑞幸咖啡被吐槽喝完3口剩下全是冰 客服:门店按配方比例制作
- 世界快消息!育碧正式宣布“单飞”:E3展会再失重要参展商
- 独此一家!真我GT Neo5 SE梦幻续航组合:100W快充+5500mAh电池
- 每日速递:迪士尼《小美人鱼》真人电影确认引进内地:或5月上映
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
全球今头条!Go语言:通过TDD驱动测试开发为同事写的程序优化提速——初次接触并发与channel
正文:
假如同事已经写了一个 CheckWebsites
的函数检查 URL 列表的状态。
package concurrencytype WebsiteChecker func(string) boolfunc CheckWebsites(wc WebsiteChecker, urls []string) map[string]bool { results := make(map[string]bool) for _, url := range urls { results[url] = wc(url) } return results}它返回一个 map,由每个 url 检查后的得到的布尔值组成,成功响应的值为
true
,错误响应的值为 false
。你还必须传入一个 WebsiteChecker
处理单个 URL 并返回一个布尔值。它会被函数调用以检查所有的网站。使用 依赖注入允许在不发起真实 HTTP 请求的情况下测试函数,这使测试变得可靠和快速。这是他们写的测试:package concurrencyimport ( "reflect" "testing")func mockWebsiteChecker(url string) bool { if url == "waat://furhurterwe.geds" { return false } return true}func TestCheckWebsites(t *testing.T) { websites := []string{ "http://google.com", "http://blog.gypsydave5.com", "waat://furhurterwe.geds", } actualResults := CheckWebsites(mockWebsiteChecker, websites) want := len(websites) got := len(actualResults) if want != got { t.Fatalf("Wanted %v, got %v", want, got) } expectedResults := map[string]bool{ "http://google.com": true, "http://blog.gypsydave5.com": true, "waat://furhurterwe.geds": false, } if !reflect.DeepEqual(expectedResults, actualResults) { t.Fatalf("Wanted %v, got %v", expectedResults, actualResults) }}
该功能在生产环境中被用于检查数百个网站。但是你的同事开始抱怨它速度很慢,所以他们请你帮忙为程序提速。
(资料图片)
写一个测试
首先我们对 CheckWebsites
做一个基准测试,这样就能看到我们修改的影响。
package concurrencyimport ( "testing" "time")func slowStubWebsiteChecker(_ string) bool { time.Sleep(20 * time.Millisecond) return true}func BenchmarkCheckWebsites(b *testing.B) { urls := make([]string, 100) for i := 0; i < len(urls); i++ { urls[i] = "a url" } for i := 0; i < b.N; i++ { CheckWebsites(slowStubWebsiteChecker, urls) }}
基准测试使用一百个网址的 slice 对 CheckWebsites
进行测试,并使用 WebsiteChecker
的伪造实现。
slowStubWebsiteChecker
故意放慢速度。它使用 time.Sleep
明确等待 20 毫秒,然后返回 true。
当我们运行基准测试时使用 go test -bench=.
命令 (如果在 Windows Powershell 环境下使用 go test -bench="."
):
CheckWebsite
经过基准测试的时间为 2001269572纳秒,大约 2 秒。让我们尝试去让它运行得更快。编写足够的代码让它通过
现在我们终于可以谈论并发了,以下内容是为了说明「不止一件事情正在进行中」。这是我们每天很自然在做的事情。比如,今天早上我泡了一杯茶。我放上水壶,然后在等待它煮沸时,从冰箱里取出了牛奶,把茶从柜子里拿出来,找到我最喜欢的杯子,把茶袋放进杯子里,然后等水壶沸了,把水倒进杯子里我 没有做的事情是放上水壶,然后呆呆地盯着水壶等水煮沸,然后在煮沸后再做其他事情。如果你能理解为什么第一种方式泡茶更快,那你就可以理解我们如何让CheckWebsites
变得更快。与其等待网站响应之后再发送下一个网站的请求,不如告诉计算机在等待时就发起下一个请求。通常在 Go 中,当调用函数 doSomething()
时,我们等待它返回(即使它没有值返回,我们仍然等待它完成)。我们说这个操作是 阻塞的 —— 它让我们等待它完成。Go 中不会阻塞的操作将在称为 goroutine的单独 进程中运行。将程序想象成从上到下读 Go 的 代码,当函数被调用执行读取操作时,进入每个函数「内部」。当一个单独的进程开始时,就像开启另一个 reader(阅读程序)在函数内部执行读取操作,原来的 reader 继续向下读取 Go 代码。要告诉 Go 开始一个新的 goroutine,我们把一个函数调用变成 go
声明,通过把关键字 go
放在它前面:go doSomething()
。package concurrencytype WebsiteChecker func(string) boolfunc CheckWebsites(wc WebsiteChecker, urls []string) map[string]bool { results := make(map[string]bool) for _, url := range urls { go func() { results[url] = wc(url) }() } return results}
因为开启 goroutine 的唯一方法就是将 go
放在函数调用前面,所以当我们想要启动 goroutine 时,我们经常使用 匿名函数(anonymous functions)。一个匿名函数文字看起来和正常函数声明一样,但没有名字(意料之中)。你可以在 上面的 for
循环体中看到一个。
匿名函数有许多有用的特性,其中两个上面正在使用。首先,它们可以在声明的同时执行 —— 这就是匿名函数末尾的 ()
实现的。其次,它们维护对其所定义的词汇作用域的访问权 —— 在声明匿名函数时所有可用的变量也可在函数体内使用。
上面匿名函数的主体和之前循环体中的完全一样。唯一的区别是循环的每次迭代都会启动一个新的 goroutine,与当前进程(WebsiteChecker
函数)同时发生,每个循环都会将结果添加到 results
map 中。
但是当我们执行 go test
:
-------- FAIL: TestCheckWebsites (0.00s) CheckWebsites_test.go:31: Wanted map[http://google.com:true http://blog.gypsydave5.com:true waat://furhurterwe.geds:false], got map[]FAILexit status 1FAIL github.com/gypsydave5/learn-go-with-tests/concurrency/v1 0.010s
你可能不会得到这个结果。你可能会得到一个 panic 信息,这个稍后再谈。如果你得到的是那些结果,不要担心,只要继续运行测试,直到你得到上述结果。或假装你得到了,这取决于你。欢迎来到并发编程的世界:如果处理不正确,很难预测会发生什么。别担心 —— 这就是我们编写测试的原因,当处理并发时,测试帮助我们预测可能发生的情况。
让我们困惑的是,原来的测试 WebsiteChecker
现在返回空的 map。哪里出问题了?
for
循环开始的 goroutines
没有足够的时间将结果添加结果到 results
map 中;WebsiteChecker
函数对于它们来说太快了,以至于它返回时仍为空的 map。为了解决这个问题,我们可以等待所有的 goroutine 完成他们的工作,然后返回。两秒钟应该能完成了,对吧?package concurrencyimport "time"type WebsiteChecker func(string) boolfunc CheckWebsites(wc WebsiteChecker, urls []string) map[string]bool { results := make(map[string]bool) for _, url := range urls { go func() { results[url] = wc(url) }() } time.Sleep(2 * time.Second) return results}
现在当我们运行测试时获得的结果(如果没有得到 —— 参考上面的做法):
-------- FAIL: TestCheckWebsites (0.00s) CheckWebsites_test.go:31: Wanted map[http://google.com:true http://blog.gypsydave5.com:true waat://furhurterwe.geds:false], got map[waat://furhurterwe.geds:false]FAILexit status 1FAIL github.com/gypsydave5/learn-go-with-tests/concurrency/v1 0.010s
这不是很好 - 为什么只有一个结果?我们可以尝试通过增加等待的时间来解决这个问题 —— 如果你愿意,可以试试。但没什么作用。这里的问题是变量 url
被重复用于 for
循环的每次迭代 —— 每次都会从 urls
获取新值。但是我们的每个 goroutine 都是 url
变量的引用 —— 它们没有自己的独立副本。所以他们 都会写入在迭代结束时的 url
—— 最后一个 url。这就是为什么我们得到的结果是最后一个 url。
解决这个问题:
import ( "time")type WebsiteChecker func(string) boolfunc CheckWebsites(wc WebsiteChecker, urls []string) map[string]bool { results := make(map[string]bool) for _, url := range urls { go func(u string) { results[u] = wc(u) }(url) } time.Sleep(2 * time.Second) return results}
通过给每个匿名函数一个参数 url(u
),然后用 url
作为参数调用匿名函数,我们确保 u
的值固定为循环迭代的 url
值,重新启动 goroutine
。u
是 url
值的副本,因此无法更改。
现在,如果你幸运的话,你会得到:
PASSok github.com/gypsydave5/learn-go-with-tests/concurrency/v1 2.012s
但是,如果你不走运(如果你运行基准测试,这很可能会发生,因为你将发起多次的尝试)。
fatal error: concurrent map writes
goroutine 8 [running]:runtime.throw(0x12c5895, 0x15) /usr/local/Cellar/go/1.9.3/libexec/src/runtime/panic.go:605 +0x95 fp=0xc420037700 sp=0xc4200376e0 pc=0x102d395runtime.mapassign_faststr(0x1271d80, 0xc42007acf0, 0x12c6634, 0x17, 0x0) /usr/local/Cellar/go/1.9.3/libexec/src/runtime/hashmap_fast.go:783 +0x4f5 fp=0xc420037780 sp=0xc420037700 pc=0x100eb65github.com/gypsydave5/learn-go-with-tests/concurrency/v3.WebsiteChecker.func1(0xc42007acf0, 0x12d3938, 0x12c6634, 0x17) /Users/gypsydave5/go/src/github.com/gypsydave5/learn-go-with-tests/concurrency/v3/websiteChecker.go:12 +0x71 fp=0xc4200377c0 sp=0xc420037780 pc=0x12308f1runtime.goexit() /usr/local/Cellar/go/1.9.3/libexec/src/runtime/asm_amd64.s:2337 +0x1 fp=0xc4200377c8 sp=0xc4200377c0 pc=0x105cf01created by github.com/gypsydave5/learn-go-with-tests/concurrency/v3.WebsiteChecker /Users/gypsydave5/go/src/github.com/gypsydave5/learn-go-with-tests/concurrency/v3/websiteChecker.go:11 +0xa1
... many more scary lines of text ...
这看上去冗长、可怕,我们需要深呼吸并阅读错误:fatal error: concurrent map writes
。有时候,当我们运行我们的测试时,两个 goroutines 完全同时写入 results
map。Go 的 Maps 不喜欢多个事物试图一次性写入,所以就导致了 fatal error
。
这是一种 race condition(竞争条件),当软件的输出取决于事件发生的时间和顺序时,因为我们无法控制,bug 就会出现。因为我们无法准确控制每个 goroutine 写入结果 map 的时间,两个 goroutines 同一时间写入时程序将非常脆弱。
Go 可以帮助我们通过其内置的 race detector 来发现竞争条件。要启用此功能,请使用 race
标志运行测试:go test -race
你应该得到一些如下所示的输出:
==================WARNING: DATA RACEWrite at 0x00c420084d20 by goroutine 8: runtime.mapassign_faststr() /usr/local/Cellar/go/1.9.3/libexec/src/runtime/hashmap_fast.go:774 +0x0 github.com/gypsydave5/learn-go-with-tests/concurrency/v3.WebsiteChecker.func1() /Users/gypsydave5/go/src/github.com/gypsydave5/learn-go-with-tests/concurrency/v3/websiteChecker.go:12 +0x82
Previous write at 0x00c420084d20 by goroutine 7: runtime.mapassign_faststr() /usr/local/Cellar/go/1.9.3/libexec/src/runtime/hashmap_fast.go:774 +0x0 github.com/gypsydave5/learn-go-with-tests/concurrency/v3.WebsiteChecker.func1() /Users/gypsydave5/go/src/github.com/gypsydave5/learn-go-with-tests/concurrency/v3/websiteChecker.go:12 +0x82
Goroutine 8 (running) created at: github.com/gypsydave5/learn-go-with-tests/concurrency/v3.WebsiteChecker() /Users/gypsydave5/go/src/github.com/gypsydave5/learn-go-with-tests/concurrency/v3/websiteChecker.go:11 +0xc4 github.com/gypsydave5/learn-go-with-tests/concurrency/v3.TestWebsiteChecker() /Users/gypsydave5/go/src/github.com/gypsydave5/learn-go-with-tests/concurrency/v3/websiteChecker_test.go:27 +0xad testing.tRunner() /usr/local/Cellar/go/1.9.3/libexec/src/testing/testing.go:746 +0x16c
Goroutine 7 (finished) created at: github.com/gypsydave5/learn-go-with-tests/concurrency/v3.WebsiteChecker() /Users/gypsydave5/go/src/github.com/gypsydave5/learn-go-with-tests/concurrency/v3/websiteChecker.go:11 +0xc4 github.com/gypsydave5/learn-go-with-tests/concurrency/v3.TestWebsiteChecker() /Users/gypsydave5/go/src/github.com/gypsydave5/learn-go-with-tests/concurrency/v3/websiteChecker_test.go:27 +0xad testing.tRunner() /usr/local/Cellar/go/1.9.3/libexec/src/testing/testing.go:746 +0x16c==================
细节还是难以阅读 - 但 WARNING: DATA RACE
相当明确。阅读错误的内容,我们可以看到两个不同的 goroutines 在 map 上执行写入操作:
Write at 0x00c420084d20 by goroutine 8:.
正在写入相同的内存块
Previous write at 0x00c420084d20 by goroutine 7:
最重要的是,我们可以看到发生写入的代码行:
/Users/gypsydave5/go/src/github.com/gypsydave5/learn-go-with-tests/concurrency/v3/websiteChecker.go:12
和 goroutines 7 和 8 开始的代码行号:
/Users/gypsydave5/go/src/github.com/gypsydave5/learn-go-with-tests/concurrency/v3/websiteChecker.go:11
你需要知道的所有内容都会打印到你的终端上 - 你只需耐心阅读就可以了。
Channels
我们可以通过使用 channels协调我们的 goroutines 来解决这个数据竞争。channels 是一个 Go 数据结构,可以同时接收和发送值。这些操作以及细节允许不同进程之间的通信。
在这种情况下,我们想要考虑父进程和每个 goroutine 之间的通信,goroutine 使用 url 来执行 WebsiteChecker
函数。
package concurrencytype WebsiteChecker func(string) booltype result struct { string bool}func CheckWebsites(wc WebsiteChecker, urls []string) map[string]bool { results := make(map[string]bool) resultChannel := make(chan result) for _, url := range urls { go func(u string) { resultChannel <- result{u, wc(u)} }(url) } for i := 0; i < len(urls); i++ { result := <-resultChannel results[result.string] = result.bool } return results}
除了 results
map 之外,我们现在还有一个 resultChannel
的变量,同样使用 make
方法创建。chan result
是 channel 类型的 —— result
的 channel。新类型的 result
是将 WebsiteChecker
的返回值与正在检查的 url 相关联 —— 它是一个 string
和 bool
的结构。因为我们不需要任何一个要命名的值,它们中的每一个在结构中都是匿名的;这在很难知道用什么命名值的时候可能很有用。
现在,当我们迭代 urls 时,不是直接写入 map
,而是使用 send statement将每个调用 wc
的 result
结构体发送到 resultChannel
。这使用 <-
操作符,channel 放在左边,值放在右边:
// send statementresultChannel <- result{u, wc(u)}
下一个 for
循环为每个 url 迭代一次。 我们在内部使用 receive expression,它将从通道接收到的值分配给变量。这也使用 <-
操作符,但现在两个操作数颠倒过来:现在 channel 在右边,我们指定的变量在左边:
// receive expressionresult := <-resultChannel
然后我们使用接收到的 result
更新 map。
results
map 的时间,确保每次写入一个结果。虽然 wc
的每个调用都发送给结果通道,但是它们在其自己的进程内并行发生,因为我们将结果通道中的值与接收表达式一起逐个处理一个结果。我们已经将想要加快速度的那部分代码并行化,同时确保不能并发的部分仍然是线性处理。我们使用 channel 在多个进程间通信。当我们运行基准时:20994821 纳秒 —— 0.02 秒,速度大约是最初函数的一百倍,这是非常成功的。
总结:
某种程度说,我们已经参与了 CheckWebsites
函数的一个长期重构;输入和输出从未改变,它只是变得更快了。但是我们所做的测试以及我们编写的基准测试允许我们重构 CheckWebsites
,让我们有信心保证软件仍然可以工作,同时也证明它确实变得更快了。
在使它更快的过程中,我们明白了
- goroutines是 Go 的基本并发单元,它让我们可以同时检查多个网站。
- anonymous functions(匿名函数),我们用它来启动每个检查网站的并发进程。
- channels,用来组织和控制不同进程之间的交流,使我们能够避免 race condition(竞争条件)的问题。
- the race detector(竞争探测器)帮助我们调试并发代码的问题。
让它运作,使它正确,使它快速「运作」是通过测试,「正确」是重构代码,而「快速」是优化代码以使其快速运行。一旦我们使程序可以正确运行,我们能做的就只有使它快速。很幸运,我们得到的代码已经被证明是可以运作的,并且不需要重构。在另外两个步骤执行之前,我们绝不应该试图「使它快速」,因为
过早的优化是万恶之源—— Donald Knuth
关键词:
-
全球今头条!Go语言:通过TDD驱动测试开发为同事写的程序优化提速——初次接触并发与channel
正文:假如同事已经写了一个CheckWebsites的函数检查URL列表的状态。packageconcurrencytypeWebsiteCheckerfunc(string)b
来源: -
速递!【Visual Leak Detector】配置项 MaxTraceFrames
使用VLD内存泄漏检测工具辅助开发时整理的学习笔记。本篇介绍VLD配置文件中配置项MaxTraceFrames的使用方法。
来源: 全球今头条!Go语言:通过TDD驱动测试开发为同事写的程序优化提速——初次接触并发与channel
【世界时快讯】非看不可的Redis持久化
选择排序
速递!【Visual Leak Detector】配置项 MaxTraceFrames
flash8怎么下载到电脑上?Flash8的序列号是多少?
大连地铁敞门行驶 线路刚开12天:客服称“原因正在调查”
快资讯丨00后女生毕业当猪场保育员:她认为这行业很有潜力
世界快资讯丨微软反戈一击 反垄断战火引至日本本土
当前头条:东南亚出游降温:机票降幅达40%
环球新动态:机器学习基础06DAY
数据密集型应用存储与检索设计
当前头条:范畴论:迷人的数学花园
环球观天下!智能存储重磅上线:低成本闲时转码
【天天快播报】促消费,振内需,康佳加速业务高质量发展
世界第一名宇航员!尤里·加加林坠机遇难地点照片首次公开
每日看点!真的可以免费坐高铁了!用12306积分兑换:官方教程收好
焦点速递!杭州地铁现打工人专线 网友:通勤都不让闲着
环球观察:《指环王:力量之戒》片场马匹死亡 动保组织谴责:剥削动物
魅族20系列大杯曝光:120Hz E6直屏、12GB+512GB组合
焦点快报!实验一 密码引擎-2-电子钥匙功能测试
CNStack 虚拟化服务:实现虚拟机和容器资源的共池管理
每日视讯:ChatGPT软件技术栈解密
天天微速讯:具有FTP、FTPS和sftp功能的文本编辑器——EditPlus功能介绍
今日热搜:【解答】MySQL MTR的实现原理与优势
核磁共振增强剂的危害_核磁共振增强剂的危害
环球热文:高德、阿里云发布全新车路协同方案 夜间开车像开了上帝视角
世界热文:瑞幸咖啡被吐槽喝完3口剩下全是冰 客服:门店按配方比例制作
世界快消息!育碧正式宣布“单飞”:E3展会再失重要参展商
独此一家!真我GT Neo5 SE梦幻续航组合:100W快充+5500mAh电池
每日速递:迪士尼《小美人鱼》真人电影确认引进内地:或5月上映
世界短讯!关于ChatGPT的一些信息,我画了一张思维导图
当前头条:前端设计模式——解释器模式
世界热点!各部队加强即将退役人员保密教育的一组见闻
焦点速递!男子2天喝4顿后死亡 起诉店家获赔:医生称如此喝酒很伤身
全球实时:价格相差数倍!智能手表比智能手环强在哪里?
昔日明星掌机落幕:任天堂正式关闭3DS游戏商店
最新消息:李想:攻破燃油车 需3步
当前简讯:任天堂爆款续作!《塞尔达传说:王国之泪》新实机今晚公布:5月12日发售
全球今热点:头铁面试官:一个小小的 System.out.println 硬是考了我半个小时,被问懵了。。
【天天播资讯】《Flask Web 开发指南 pt.1》
环球信息:日本北海道一养鸡场发生禽流感疫情
库克喊话:苹果和中国市场30年来密切关联 我们相互成长
今日热讯:告别物理卡槽!iPhone 15将进一步普及eSIM:水货机今后更难了
老人推倒摩托继承人被判赔1.6万元:车主直言被网曝 老人违法不该被宽恕
全球简讯:【国际大宗商品早报】隔夜外盘商品大面积反弹 美油涨超5%芝加哥农产品全线上涨
全球快报:最“丑”绿色车牌或在2年内取消 网友热议电车优待早该结束!国人将车牌代表面子
全球信息:2022年中国市场最畅销10款手机:国人狂买iPhone 13 高端安卓泪奔
天天视讯!昔日超市霸主 家乐福中国内地首店关闭:在北京开了28年
焦点快播:禁售时间已明确 油车还能开多久?中石油回应:新能源拐点还有很长路
天天微头条丨读Java性能权威指南(第2版)笔记30_Java服务器
世界热点评!Linux -mv命令的10个实用例子
全球看热讯:日本动漫演唱会_日本动漫
环球信息:【Visual Leak Detector】配置项 MaxDataDump
C++ 整理
OpenYurt v1.2 新版本深度解读(三):五步搭建一个OpenYurt集群
焦点速读:海外工具站 2022 复盘:商业认知篇
环球关注:泪目!孩子给离世父亲发短信被回复:爸爸也想你
1只花豹偷袭2只大猩猩:居然 全死了?
环球今日讯!别等魔兽国服了 暴雪今日开放全新服务器:自己单干
当蒂法换上《生化4》艾达王的装束:淡妆浓抹总相宜
全球观速讯丨软件、电影、游戏都“免费” 俄罗斯称盗版不再违法:要让奈飞破产
环球看点!樊小纯
前沿热点:美团面试:熟悉哪些JVM调优参数?
全球快看:基于.NET Core + Jquery实现文件断点分片上传
北京白领通勤天花板,单手拎起10秒折叠,网友:老板我需要
今日讯!针刺成小儿科?埃安官宣弹匣电池2.0枪击试验发布会
世界微资讯!手撕HashMap
每日资讯:一些面试高频题目
Synchronized详解
第134篇:解决浏览器的CORS跨域问题(CORS policy: Cross origin requests are only supported for p
环球观速讯丨《生化危机4:重制版》DLC正在开发中 艾达王是你的了
每日快播:深圳暴雨致航班取消 旅客情绪崩溃 跪求起飞 机场回应
环球通讯!全明星的三大遗憾,成就了这场本土篮球盛宴的缺憾之美
【Visual Leak Detector】配置项 AggregateDuplicates
Python毕业设计推荐
实时焦点:RTX 4070定了!还是你们讨厌的192位显存
每日看点!彻底没救了!《Forspoken》发售2个月后:RTX 4090依旧无法60帧
【播资讯】100亿捐款建大学 曹德旺:对标美国斯坦福 每个学生补贴5万
每日信息:做出莫斯利安的光明乳业:掉队了
女员工请假做试管婴儿被拒遭辞退 法院判了:恢复合同
环球观察:Vue 核心(二)
观焦点:HDFS Short-Circuit Local Reads
货币市场日报:3月27日
热消息:4月10日上市 福特F-150猛禽烈焰风暴特别版官图发布 为中国市场而
能抄底了?一汽奥迪补贴经销商清库存 明星车型降价近10万
每日看点!马云回国首谈ChatGPT:机器只有“芯”而人有“心”
国产车赢麻了!报告:中国品牌占俄罗斯新车销量近40%
焦点信息:“高端家用车”?比亚迪汉DM-i试驾 极致的油耗和空间
天天视讯!国产两轮电动车龙头!雅迪2022年营收310亿创纪录:电动自行车销量大增
焦点!通胀压力缓解避险情绪收敛 日债收益率周一全线回升
世界速读:商品日报(3月27日):沪锡领涨纯碱09合约增仓上行 苹果大幅下挫跌超4%
速读:前备箱门锁失灵?特斯拉扩大召回进口Model S
京东方iPhone 15灵动岛屏被曝漏光 苹果搬来三星救火:提前生产
天天热点评!女子赏花站梨树枝头甩衣狂摇 拍摄者:花瓣掉落一地
观热点:女子吃自助餐将店内甲鱼煮食 网友:是个狠人
乌鲁木齐周生生黄金价格多少钱一克(2023年3月27日)
新动态:CodeIgnitor 3.0.x 之 db 类实现机制
第一次博客
环球热点评!小皮Windows web面板漏洞详解
世界观速讯丨【原型设计工具】上海道宁为您提供Justinmind,助力您在几分钟内形成原型,并现场测试,无需编写任何代码