Press "Enter" to skip to content

编程新手如何通过ChatGPT一天完成一个MVP产品

声明:这篇文章不是 ChatGPT 写的,但大量素材来自 ChatGPT。

前言

本着在工作学习的各种场景打造多个 AI 助手,让自己只关注和处理最核心事情的初衷,昨天花了一天时间从设计、编码到调试通过,完成了基于 OpenAI 构建的第一个 MVP 产品 —— 翻译助手(第二个 MVP 产品字幕助手用于自动为视频加上中英文字幕也以完工,第三个 MVP 产品在路上),该助手从网页批量爬取、HTML 预处理到调用 OpenAI 开放接口完成中文翻译和格式优化,实现了技术文档翻译这个场景全流程 90% 工作的自动化,剩余 10% 是方案设计、工作流编排和最后的代码调试、结果审核,也就是我认为的最核心的事情。

与此同时,为了尽可能模拟一个面向未知领域的编程新手 ,在此过程中,80%以上的代码是面向 ChatGPT 编码的,即告诉 ChatGPT 我的需求,然后让它给我生成相应的代码。整个开发过程还是非常顺畅的,不得不说,生产效率相比之前面向 Google 编程还是有非常大提升的。

如果你还没有 ChatGPT 账号,请参考这篇教程获取: ChatGPT 终极指南。

在今天这篇文章中,我将尽可能还原翻译助手这个 MVP 产品实现的所有细节,给大家展示如何面向 ChatGPT 编程,如何有效利用这个 AI 工具提高工作效率,以及如何围绕 OpenAI(ChatGPT 背后的公司)提供的开放接口构建 AI 产品,最后谈谈 ChatGPT 目前存在的问题,以及我们应该如何看待 AI 产品对我们工作生活带来的影响。

当然了,作为一个文本处理领域的全能小帮手,除了翻译文档、写代码之外,ChatGPT 还可以帮我们写文章。因此,在写这篇文章之前,让我们先去咨询下 ChatGPT,让它给我们梳理思路、列个提纲:

image-20230221160824703

虽然看起来像是正确的废话,但是整体思路确实就是这样是不是,所以接下来,我将按照上面的提纲来写今天这篇文章的开发流程部分。

面向 ChatGPT 开发

这个 MVP 产品是基于 Go 语言实现的,所以后续预设都是 Go 语言上下文。

产品需求

因为是 MVP 产品,所以就只实现一个核心需求 —— 以 Laravel 官网为例,批量爬取 Laravel 10 所有英文文档,然后将英文文档翻译成中文文档,最后以 Markdown 形式保存到文本文件中,以便后续使用。

用到的技术

爬虫框架

因为需要爬取网页,只有一天时间自己写来不及,通用性也不强,所以需要选择一个爬虫框架,之前我们都是 Google 搜索,现在我们可以直接问 ChatGPT:

image-20230221162042614

它会把一些比较流行的 Go 爬虫框架列举出来,并进行简单介绍,我们可以根据需求再去 Github 进行比较,选择一款最适合的,这里我选择的是 Colly。

html 转化 markdown

另一个需要用到的基础功能就是将 HTML 区块代码转化为 Markdown,这一块也有很多开源组件,还是找 ChatGPT,让它推荐:

image-20230221163339510

这里,它不仅给出答案,还给出了各自的示例代码,当然,保险起见,最好去 Github 浏览下这些项目,维护情况怎么样,是否能满足特定的业务需求,当然你在 ChatGPT 问也不是不行,但是作为最终决策,肯定是要验证下的,毕竟 ChatGPT 和搜索引擎一样,目前都是无法对结果的准确性负责的。

这里,我选择使用 blackfriday 这个库转化 Markdown,同时也使用了 bluemonday 对 HTML 代码进行修剪和净化(比如去除不必要的样式代码、元素属性以及脚本代码),这个转化处理属于调用 OpenAI 接口前的预处理,因为 OpenAI 文本翻译接口按 Token(可以看作待处理文本字符数) 收费,所以必要的清理可以有效降低成本。

文本翻译

这里的翻译使用的是 OpenAI 提供的 Text Completion 接口: https://api.openai.com/v1/completions,就不存在方案选择问题了。这里我们使用了第三方开发的 OpenAI Go SDK:github.com/sashabaranov/go-gpt3

对于组件如何使用,你都可以面向 ChatGPT 进行学习,不用再到搜索引擎反复搜索,一个个点开搜索结果页,把不同文章讲到的东西串联起来,得到整体认知,同时也能避开类似 CSDN 这种垃圾站,看文章还要关注、登录、付费。。。这种成本单个看起来不高,但是成天累月下来,还是会占用不少无效时间。至于何时学习,我觉得可以在编码的过程中用到什么学习什么,遇到问题再去求教,这样可以把效率做到最高,在最短的时间完成最多的事情。

流程设计

我们这个产品功能比较简单,不涉及到前端和数据库,所以只需要按照需求简单设计下流程就可以了:

image-20230221170646477

其中在爬取网页这块,我们需要做一些准备工作 —— 找到爬虫入口页面,分析页面 HTML 的 DOM 结构,包括列表页和详情页(列表页提取待爬取页面链接,详情页用于提取真正要爬取的内容,以 Laravel 10 文档为例,分别是 https://laravel.com/docs/10.xhttps://laravel.com/docs/10.x/requests,详情页通常有多个,这里这是举例),因为大多数爬虫框架都是基于 CSS 选择器对页面元素进行提取,Colly 也不例外,底层是基于 goquery 以 jQuery 语法实现对页面元素的匹配和提取的。

对页面结构做到心中有数之后,因为其他两个功能模块比较简单,就可以直接开始编写代码了。

编写代码

爬虫模块

前面我们已经选取了 Colly 作为爬虫框架,作为一个编程新手,我不知道怎么使用它,所以我们需要咨询 ChatGPT:

image-20230221184049021
image-20230221222502318

ChatGPT 除了提供 Colly 的示例代码,还会给代码注释,以及对整个代码执行的流程做解释,服务非常周到,其实有了这样的能力,基于 ChatGPT 去阅读任何语言/框架/算法的源码,都非常轻松了。比如,我们想要学习 Go 协程的底层实现源码,可以直接贴代码+咨询 ChatGPT,而不是一边自己读源码,一边去查 Google,所见即所得,非常高效,这也是我认为 ChatGPT 会成为下一代搜索引擎的原因,至少比现在的搜索引擎高效 —— 让获取知识和答案的路径更短,用户可以以更快地速度、更短的时间所见即所得获取答案。

了解了 Colly 爬虫框架的基本用法之后,接下来,就是根据我们业务要爬取的页面结构编写对应的爬取业务代码了。前面我们提到,爬取文档分两步,先要提取所有要爬取的文档详情页,再去详情页爬取真正的文档内容。

1)我们可以在爬虫入口页面 https://laravel.com/docs/10.x 的左边栏提取所有文档详情页链接:

image-20230221201133470

这些链接可以通过 CSS 筛选器 div.docs_sidebar ul li a[href] 提取。提取到页面 URL 之后,就可以访问这个 URL 进而提供文档详情页的文档内容。

2)以 https://laravel.com/docs/10.x/requests 为例,文档内容位于页面右侧主体部分,即 div#main-content 元素中的内容:

image-20230221201807178

要爬取这样的两级页面,在 Colly 框架里面怎么编码,怎么问 ChatGPT,它会给我们答案:

image-20230221223039267
image-20230221223107619

简单来说,就是定义多个 c.OnHTML 回调即可。另外这里还有一个小细节,就是 OpenAI 接口对处理的字符数是限制的,这里的细节我不展开了, 官方文档有说明,一般不超过 1000 个字符为好,所以对于文档内容不能一股脑提交给 OpenAI 接口,那样会报错,需要对文档内容做拆分,这里我以 div#main-content 下的第一级子元素为拆分条件。这种情况下,我们如何去做页面元素的提取呢?还是咨询 ChatGPT:

image-20230221223615854

这样我们就心中有数了,可以通过 * 通配符匹配 div#main-content 下的所有子元素,再结合正则表达式对子元素进行筛选,因为不是所有的子元素都是有效的:

// 在找到需要提取数据的 HTML 元素时执行的回调函数
childrenRegex := regexp.MustCompile(`^(h2|h3|h4|p|pre|table|blockquote|img)$`)
c.OnHTML("#main-content *", func(e *colly.HTMLElement) {
    // 非白名单标签退出不处理
    if !childrenRegex.MatchString(e.Name) {
        return
    }

结合上面的认知,我们编写爬虫模块代码如下:

package main
​
import (
    "fmt"
    "regexp"
    "strings"
    "sync"
​
    "github.com/gocolly/colly/v2"
)
​
func main() {
    // 创建一个新的爬虫对象,同步执行,保证爬取页面元素的顺序
    c := colly.NewCollector()
​
    // 保存访问过的 URL,避免重复访问
    visited := make(map[string]bool)
    // 初始化 blocks 容器
    blocks := make(map[string][]string)
​
    // 在请求发送之前执行的回调函数
    c.OnRequest(func(r *colly.Request) {
        fmt.Println("Visiting", r.URL.String())
    })
​
    // 在请求响应之后执行的回调函数
    c.OnResponse(func(r *colly.Response) {
        fmt.Println("Response received for", r.Request.URL.String())
    })
​
    // 在找到链接元素时执行的回调函数
    c.OnHTML("div.docs_sidebar ul li a[href]", func(e *colly.HTMLElement) {
        path := e.Attr("href")
        // 只处理 /docs/10.x 开头且未访问过的链接
        if !strings.HasPrefix(path, "/docs/10.x") || visited[path] {
            return
        }
        visited[path] = true
        if path != "/docs/10.x/requests" { // 测试只爬取一个页面
            return
        }
        c.Visit(e.Request.AbsoluteURL(path))
    })
​
    // 在找到需要提取数据的 HTML 元素时执行的回调函数
    childrenRegex := regexp.MustCompile(`^(h2|h3|h4|p|pre|table|blockquote|img)$`)
    c.OnHTML("#main-content *", func(e *colly.HTMLElement) {
        // 非白名单标签退出不处理
        if !childrenRegex.MatchString(e.Name) {
            return
        }
        // 获取当前页面pathid
        path := e.Request.URL.Path
        pageId := strings.TrimPrefix(path, "/docs/10.x/")
        if path == "/docs/10.x" || pageId == "" { // 非文档页面退出不处理
            return
        }
        // 文本内容为空,则推出不处理
        if e.DOM.Text() == "" {
            return
        }
        // 将 HTML 区块代码保存到 map 中
        blockHtml, _ := e.DOM.Html()
        var outerHtml string
        if e.Name != "p" {
            outerHtml = "<" + e.Name + ">" + blockHtml + "</" + e.Name + ">" // 保留标签,比如标题、引用、表格、代码等
        } else {
            outerHtml = blockHtml // 文本段落不保留标签
        }
        // 通过转化 Markdown 去除无效的 HTML 标签,降低内存使用率
        cleanBlock := html2Md(outerHtml)
        if cleanBlock == "" {
            return
        }
        blocks[pageId] = append(blocks[pageId], cleanBlock)
    })
​
    // 在爬取所有页面结束时执行的回调函数,可以在这里调用 OpenAI 接口进行文本翻译
    c.OnScraped(func(r *colly.Response) {
        ...
    })
​
    // 发起 HTTP 请求
    c.Visit("https://laravel.com/docs/10.x")
}

这里需要注意的是为了简化页面内容拆分后的有序性,我把爬取逻辑设置为同步串行,而不是异步并发,因为这里主要是测试和跑通流程,先不考虑性能问题。

如果你想要了解提取页面元素的核心函数 OnHTML 的执行机制,以及背后是否是并发处理,也可以随时咨询 ChatGPT:

image-20230221224337016
HTML预处理

其实在上面的代码中,已经包含了 HTML 预处理函数 html2Md 的调用,之所以要做 HTML 预处理,这既是为了降低 OpenAI 接口的费用(按处理字符数收钱),也是为了降低内存的使用率,我们是在处理完成后,才将内容区块存放到容器的,HTML 的预处理逻辑也非常简单,就是调用 blackfriday 和 bluemonday 这两个包分别进行 Markdown 转化和 HTML 修整净化:

import (
    "strings"
​
    "github.com/microcosm-cc/bluemonday"
    "github.com/russross/blackfriday/v2"
)
​
func html2Md(html string) string {
    // 将html转换为markdown
    unsafe := blackfriday.Run([]byte(html))
    // 净化 HTML
    result := string(bluemonday.UGCPolicy().SanitizeBytes(unsafe))
    return result
}
调用 OpenAI 接口

完成上述工作后,所有 Laravel 10 文档内容其实就已经存放到字典容器中,并按照页面 ID 进行了隔离,我们只需要遍历这个容器,针对每个区块依次调用 OpenAI 提供的 Text Completion 接口就好了,这里我也做了一点小优化,就是将较小的区块进行合并(兼顾请求次数太多,请求太频繁也会报错):

for pageId, html := range blocks {
     var resultText strings.Builder
     var err error
     var blockBus strings.Builder
     for _, block := range html {
         // 如果是代码区块,则直接写入结果,不翻译(降低失败率,有些代码片段很长,而且代码不需要翻译,浪费成本):
         if strings.Contains(block, "
") {
             resultText.WriteString(block)
             continue
         }
         // 如果blockbus和当前区块长度已经超过 1000,并且blockbus不为空,则发车
         if blockBus.Len() > 0 && (blockBus.Len()+len(block)) > 1000 {
             // 调用 OpenAI 接口进行文本翻译,格式后处理
             blockResult, err := callOpenAI(blockBus.String())
             if err != nil {
                 fmt.Println("调用 OpenAI 处理文本失败:", err)
                 continue
             }
             resultText.WriteString(blockResult)
             // 清空缓冲区
             blockBus.Reset()
         }
         blockBus.WriteString(block)
     }
     // 将翻译处理结果写入Markdown文件
     err = writeToFile(pageId, resultText.String())
     if err != nil {
         fmt.Println("写入Markdown文件失败:", err)
         return
     }
 }

作为 OpenAI 新人,我并不知道怎么调用它的接口,还是面向 ChatGPT 编程:

image-20230221225006263
image-20230221225051595

可以看到,ChatGPT 给了我们非常详细的步骤,包括去 OpenAI 注册账号,拿到 API_KEY, 我们把稍作调整,整合到调用 OpenAI 的 callOpenAI 函数中即可:

func callOpenAI(text string) (string, error) {
    api_key := os.Getenv("OPENAI_SECRET_KEY")
    prompt := fmt.Sprintf("将网页主体内容翻译成中文,以markdown格式输出,中英文字符串之间用空格分隔:\n%s", text)
​
    client := gogpt.NewClient(api_key)
    req := gogpt.CompletionRequest{
        Model:       "text-davinci-003",
        Prompt:      prompt,
        Temperature: 0,
        MaxTokens:   3000,
    }
    resp, err := client.CreateCompletion(context.Background(), req)
    if err != nil {
        fmt.Println("调用 OpenAI 接口失败:", err)
        return "", err
    }
​
    return resp.Choices[0].Text, err
}
保存到 Markdown 文件

最后,我们要将 OpenAI 返回的翻译后的文本按照文档ID组合起来,写入到 markdown 文件,作为编程新人,我不知道怎么把文本内容存放到文件,问 ChatGPT:

image-20230221225325331

把它返回的示例代码整合到 writeToFile 函数即可:

func writeToFile(pageId, text string) error {
    // 打开文件,如果文件不存在则创建
    file, err := os.OpenFile("./docs/"+pageId+".md", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
    if err != nil {
        return err
    }
    defer file.Close()
​
    // 创建一个写入器,使用缓存写入文件
    writer := bufio.NewWriter(file)
​
    // 写入文本
    _, err = writer.WriteString(text)
    if err != nil {
        return err
    }
​
    // 刷新缓存,确保文本被写入文件
    err = writer.Flush()
    if err != nil {
        return err
    }
​
    return nil
}

调试通过

至此,我们就完成了业务员代码的编写工作,有了 ChatGPT 这个助理,是不是很高效?这种感觉就像你是个小组 Leader,下面有几个人,每次接到任务,你根据需求编写技术方案,然后对任务做拆分,分给小组内不同的人去完成,最后再把他们提交的模块代码组合起来,调试运行通过:

image-20230221225542114

如果你觉得某些区块处理的格式不对,可以继续让 ChatGPT 帮你优化:

image-20230221225709536

PS:这里没有涉及到很多正则匹配和数据库操作,ChatGPT 在帮你写 正则和 SQL 语句方面也非常成熟,有了 ChatGPT,再也不用害怕写复杂正则表达式和 SQL 查询语句了。

由于国内已经无法访问 OpenAI API 接口,你可以参照 这篇教程设置代理访问。

更进一步

当然了,翻译助手这个基于 OpenAI 的 MVP 产品目前还很简单,只是为了完成核心需求要求的功能,并没有做任何性能、系统扩展性、用户体验更好这些层面的考虑,这些需要留待后续迭代去升级,但同时也是你从日常搬砖中解放出来后应该真正花心思去考虑的。

更高性能

爬取文档页面和提取页面元素都是可以朝着异步并行的方向去提升性能的,还有针对 OpenAI 接口的调用,目前也是同步的,不过除了为了简化系统,这里串行调用还有一个考量 —— OpenAI 的接口调用很贵。我昨天只是简单测试,就花掉了几美金,如果去批量爬取翻译海量文档,这个成本个人是无法承担的,不过公司而言财务方面的压力会好点:

此外 OpenAI 的接口也并不稳定,并发量上来之后经常挂掉,我在 Twitter 上也看到好多人吐槽,所以目前我觉得还不太适合大规模商业。比如之前一些比较火的 周报生成器、 浏览器翻译插件(基于 ChatGPT)都因为这方面的原因终止项目了:

系统扩展点

所谓系统扩展主要是功能通用性上的,比如爬取 Laravel 文档之外的更多页面、更多网站,这个时候,可能就需要封装出一个爬虫引擎,能够适配多个网站的不同页面提取规则。

还有就是文本翻译这块,处理 OpenAI 之外,是否可以支持更多其他第三方翻译服务,比如传统的 DeepL、谷歌翻译,以及其他的 AI 文字处理接口。

更友好使用

目前这个翻译助手只提供了命令行 CLI 版本,并且很多参数都写死在代码里了,需要做一定的解耦,如果要给开发者之外的更多人使用还要开发出更多包含图形化界面的客户端,比如桌面版、Mac版、iOS 版、安卓版、Web 版等等。

限于篇幅,这里就不做更多发散了。

ChatGPT 目前存在的问题

在文本翻译、格式处理、文章(案)写作和常规代码编写这块,ChatGPT 表现的已经相当不错了,但是也存在一些硬伤,就是无法对结果准确性负责,当然搜索引擎也不行,而且我们在获取搜索引擎可用结果这件事情上要付出的成本还更高,另外就是它也无法对一些人类看来很明显的逻辑错误问题进行甄别,看起来就是一本正经的胡说八道:

image-20230221230343168
6a95d32f7dae02f1cbacb915788b887

不过,之所以中文这块逻辑硬伤明显,可能也跟用于训练的中文互联网数据太少有关系,目前整个中文互联网对 ChatGPT 的贡献值非常低,只占比不到 0.1%:

abc18a5f070951daab1642e4af938da

当然 ChatGPT 本身也在不断进化,目前使用的 GPT-3 模型参数是 1750 亿,而下一代 GPT-4 模型使用的参数达到了惊人的 100 万亿,这个数量级和人脑的神经突触相当,这也意味着更强的学习能力、预测能力、理解能力和自然语言处理能力。

我们该如何看待 ChatGPT

很多人恐慌 ChatGPT 会替代自己,我倒不这么认为。很多新事物到来的时候,都会引起部分人的恐慌,比如照相机会不会摄人心魄,火车会不会惊动地下的祖先,事后回看,都是无稽之谈,这些新事物反而都给我们带来更多便利,让我们的生活更加美好。

人工智能大抵也是这样。

以开发者为例,引入更智能的 ChatGPT 后,你的核心职责不再是编写那些低级的、重复的、流程化的代码,而是变成一个 Leader 或者说导演的角色,领到任务后先设计方案,再进行模块拆分,把 ChatGPT 当作 worker,这个 worker 不仅是专业选手,还是全能选手,一人能干所有的活,但是它不能保证做的事情结果是正确的,最后需要你去把关、验证,再组合起来完成真正的业务需求。

ChatGPT 是你的忠实助手,为你处理一切杂务,也是你的智囊库,你可以咨询它任何事情,尤其在学习新技术的时候,虽然还有进步空间,但它显然已经是一个比搜索引擎更好的问答引擎,所以,我觉得至少目前 ChatGPT 还不能替代程序员,而作为开发者,我们要始终保持主观能动性,善于利用这个工具大幅提高工作效率,去关心更核心的事情,比如项目的流程、团队的协作、客户的需求、服务的体验、性能的优化、整体的架构,多去与人打交道,更快地提升自己。

科技向善,以人为本,无论何时,人类社会还是以人为主体,所有科技的本质,也都是为人提供服务。

那除了开发者之外,该如何更好地利用 ChatGPT 为更多人提供服务呢,毕竟它是普适的文字处理助手,而不仅限于科技界。

语言的边界决定你世界的外延,在 ChatGPT 里,你的问题决定了它对你的帮助,善于提问非常关键,这里推荐一份 ChatGPT 高级用法的 prompt 问题清单,提供了很多问题模板,帮助你优化自己的工作流: FlowGPT: Amplify your workflow with best prompts

image-20230221232634509

还有一份中文版 ChatGPT 食用指南,内含注册流程,615 个 AI 技术落地的工具和179 个使用场景: ChatGPT 应用汇总及操作手册

最后,你还可以加入学院君和他的朋友们知识星球,和我一起探索和分享更多 ChatGPT 的新玩法:

发表回复 取消回复

Sidebar

极客推荐

最新发布

  • 极客智坊支持 GPT-4o/Gemini-1.5-Flash/Kimi/DeepSeek/豆包模型&套餐价格下调&免费使用套路
  • Perplexity 如何构建 AI 产品开发新模式
  • AI Index —— 通过13张图解读AI现状
  • Headlime&HeadshotPro 创始人 —— 以100万美元出售 AI 写作项目并创建月入30万美元的 AI 照片服务
  • AI 德语导师创始人的独立创业之旅 —— 从0.01欧元到10000欧元月收入
  • Bannerbear&Browserbear 创始人 —— 月入5万美元的成功秘诀与艰辛之路
  • SiteGPT 创始人的励志故事 —— 凭借 AI 东风从副业项目到月入10万美元
  • ShipFast 创始人 —— 我的独立开发者故事:2年内从被解雇到月入6.5万美元
  • 一人企业的标杆 —— PhotoAI 创始人年入数百万美元的独立开发者故事
  • Typing Mind 创始人 —— 我的独立开发者故事:2年内从0到每月4.5万美元

热门阅读

  • Go 入门到精通教程 - 68,928 views
  • ChatGPT 终极指南 - 36,064 views
  • Go 快速入门篇(一):第一个 Go 程序 - 18,052 views
  • Go 快速入门篇(二):Go 项目工程管理示例(基于 Go Modules) - 17,117 views
  • 开篇:为什么学习 Go 语言 - 14,826 views
  • 基于 OpenAI API + Laravel 快速构建网页版 ChatGPT - 14,264 views
  • Go 数据类型篇(一):变量、作用域、常量和枚举 - 13,378 views
  • Go 快速入门篇(三):单元测试、问题定位及代码调试 - 13,073 views
  • 面向 ChatGPT 编程实现全栈开发的 18 种方法 - 12,417 views
  • Go 面向对象编程篇(二):类的定义、初始化和成员方法 - 11,222 views

热门推荐

  • Go 面向对象编程篇(三):通过组合实现类的继承和方法重写 22 votes, average: 5.00 out of 522 votes, average: 5.00 out of 522 votes, average: 5.00 out of 522 votes, average: 5.00 out of 522 votes, average: 5.00 out of 5 (5.00)
  • Go 快速入门篇(三):单元测试、问题定位及代码调试 19 votes, average: 5.00 out of 519 votes, average: 5.00 out of 519 votes, average: 5.00 out of 519 votes, average: 5.00 out of 519 votes, average: 5.00 out of 5 (5.00)
  • Go 错误处理篇(三):panic 和 recover 17 votes, average: 5.00 out of 517 votes, average: 5.00 out of 517 votes, average: 5.00 out of 517 votes, average: 5.00 out of 517 votes, average: 5.00 out of 5 (5.00)
  • Go 数据结构和算法篇(二):栈 9 votes, average: 5.00 out of 59 votes, average: 5.00 out of 59 votes, average: 5.00 out of 59 votes, average: 5.00 out of 59 votes, average: 5.00 out of 5 (5.00)
  • 基于 OpenAI API + Laravel 快速构建网页版 ChatGPT 9 votes, average: 5.00 out of 59 votes, average: 5.00 out of 59 votes, average: 5.00 out of 59 votes, average: 5.00 out of 59 votes, average: 5.00 out of 5 (5.00)
  • Go 并发编程篇(一):从多进程、多线程到协程 8 votes, average: 5.00 out of 58 votes, average: 5.00 out of 58 votes, average: 5.00 out of 58 votes, average: 5.00 out of 58 votes, average: 5.00 out of 5 (5.00)
  • Go 数据结构和算法篇(十八):平衡二叉树 7 votes, average: 5.00 out of 57 votes, average: 5.00 out of 57 votes, average: 5.00 out of 57 votes, average: 5.00 out of 57 votes, average: 5.00 out of 5 (5.00)
  • Go 数据结构和算法篇(六):选择排序 6 votes, average: 5.00 out of 56 votes, average: 5.00 out of 56 votes, average: 5.00 out of 56 votes, average: 5.00 out of 56 votes, average: 5.00 out of 5 (5.00)
  • Go 并发编程篇(二):协程实现原理及使用入门 5 votes, average: 5.00 out of 55 votes, average: 5.00 out of 55 votes, average: 5.00 out of 55 votes, average: 5.00 out of 55 votes, average: 5.00 out of 5 (5.00)
  • Go 数据结构和算法篇(十七):二叉排序(查找)树 5 votes, average: 5.00 out of 55 votes, average: 5.00 out of 55 votes, average: 5.00 out of 55 votes, average: 5.00 out of 55 votes, average: 5.00 out of 5 (5.00)

最新评论

  • Headlime&HeadshotPro 创始人 —— 以100万美元出售 AI 写作项目并创建月入30万美元的 AI 照片服务 - 极客书房发表在《 一人企业的标杆 —— PhotoAI 创始人年入数百万美元的独立开发者故事》
  • AI 德语导师创始人的独立创业之旅 —— 从0.01欧元到10000欧元月收入 - 极客书房发表在《 一人企业的标杆 —— PhotoAI 创始人年入数百万美元的独立开发者故事》
  • Bannerbear&Browserbear 创始人 —— 月入5万美元的成功秘诀与艰辛之路 - 极客书房发表在《 一人企业的标杆 —— PhotoAI 创始人年入数百万美元的独立开发者故事》
  • 极客智坊引入 GPT-4V 支持图片对话 - 极客书房发表在《 极客智坊支持 Gemini/Claude3 模型及UI交互调整》
  • 如何成为优秀的软件工程师 - 极客书房发表在《 如何提高10倍工作效率》
  • 如何成为优秀的软件工程师 - 极客书房发表在《 在软件工程中高质量工作》
  • jinhuajun发表在《 Go 并发编程篇(四):基于锁和原子操作实现并发安全》
  • gzx发表在《 Go 并发编程篇(四):基于锁和原子操作实现并发安全》
  • bella发表在《 Go 并发编程篇(三):基于共享内存实现协程通信》
  • bella发表在《 Go 并发编程篇(四):基于锁和原子操作实现并发安全》

热门标签

AI ChatGPT GeekAI Go GPT-4 Prompt SaaS SEO 一人企业 二叉树 人工智能 入门课程 函数 函数式编程 初始化 加密货币 在线收入 字符串 实现代码 工具 广告文案 微软 手册 排序算法 接口 效率 教程 数字产品 数据类型 数据结构 数组 无代码 机器学习 极客智坊 查找算法 电子商务 算法 算法复杂度 粉丝运营 股票投资 软件工程 遍历 链表 销售漏斗 面向对象编程

深圳SEO优化公司南澳网站建设设计石岩网站设计模板大鹏网站搜索优化东莞网站开发荷坳高端网站设计坂田设计网站盐田SEO按天扣费龙岗优秀网站设计坂田企业网站改版龙岗百度关键词包年推广宝安关键词按天扣费塘坑SEO按效果付费坑梓百度竞价坑梓网站优化按天收费龙岗seo网站优化光明百度网站优化西乡网站建设木棉湾英文网站建设平湖网站推广方案西乡百搜词包观澜阿里店铺运营罗湖网页制作光明seo排名罗湖网站优化东莞seo宝安百度关键词包年推广平湖高端网站设计沙井阿里店铺托管盐田网站设计模板爱联SEO按天计费歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化