1. 当你要求 GPT-4 帮你写点代码时

如下图所示,我希望 GPT-4 给我的项目 GoPool 添加一个小功能:

这时候 GPT-4 给出的回答如下:

--- 从这里开始 ---


  • 用户希望将任务队列的大小从固定值改为可配置的。
  • 当前的任务队列大小在 NewGoPool 函数中被硬编码为 1e6

为了实现这个需求,我们可以在 goPool 结构体中添加一个新的字段 taskQueueSize,并在 NewGoPool 函数中使用这个字段来初始化 taskQueue。同时,我们需要添加一个新的选项函数 WithTaskQueueSize 来允许用户在创建 GoPool 时设置任务队列的大小。

以下是修改后的代码:

package gopool

import (
"context"
"sync"
"time"
) // GoPool represents a pool of workers.
type GoPool interface {
// AddTask adds a task to the pool.
AddTask(t task)
// Wait waits for all tasks to be dispatched and completed.
Wait()
// Release releases the pool and all its workers.
Release()
// GetRunning returns the number of running workers.
Running() int
// GetWorkerCount returns the number of workers.
GetWorkerCount() int
} // task represents a function that will be executed by a worker.
// It returns a result and an error.
type task func() (interface{}, error) // goPool represents a pool of workers.
type goPool struct {
workers []*worker
workerStack []int
maxWorkers int
// Set by WithMinWorkers(), used to adjust the number of workers. Default equals to maxWorkers.
minWorkers int
// tasks are added to this channel first, then dispatched to workers. Default buffer size is 1 million.
taskQueue chan task
// Set by WithTaskQueueSize(), used to set the size of the task queue. Default is 1e6.
taskQueueSize int
// Set by WithRetryCount(), used to retry a task when it fails. Default is 0.
retryCount int
lock sync.Locker
cond *sync.Cond
// Set by WithTimeout(), used to set a timeout for a task. Default is 0, which means no timeout.
timeout time.Duration
// Set by WithResultCallback(), used to handle the result of a task. Default is nil.
resultCallback func(interface{})
// Set by WithErrorCallback(), used to handle the error of a task. Default is nil.
errorCallback func(error)
// adjustInterval is the interval to adjust the number of workers. Default is 1 second.
adjustInterval time.Duration
ctx context.Context
// cancel is used to cancel the context. It is called when Release() is called.
cancel context.CancelFunc
} // NewGoPool creates a new pool of workers.
func NewGoPool(maxWorkers int, opts ...Option) GoPool {
ctx, cancel := context.WithCancel(context.Background())
pool := &goPool{
maxWorkers: maxWorkers,
// Set minWorkers to maxWorkers by default
minWorkers: maxWorkers,
// workers and workerStack should be initialized after WithMinWorkers() is called
workers: nil,
workerStack: nil,
taskQueue: nil,
taskQueueSize: 1e6,
retryCount: 0,
lock: new(sync.Mutex),
timeout: 0,
adjustInterval: 1 * time.Second,
ctx: ctx,
cancel: cancel,
}
// Apply options
for _, opt := range opts {
opt(pool)
} pool.taskQueue = make(chan task, pool.taskQueueSize) pool.workers = make([]*worker, pool.minWorkers)
pool.workerStack = make([]int, pool.minWorkers) if pool.cond == nil {
pool.cond = sync.NewCond(pool.lock)
}
// Create workers with the minimum number. Don't use pushWorker() here.
for i := 0; i < pool.minWorkers; i++ {
worker := newWorker()
pool.workers[i] = worker
pool.workerStack[i] = i
worker.start(pool, i)
}
go pool.adjustWorkers()
go pool.dispatch()
return pool
}
package gopool

import (
"sync"
"time"
) // Option represents an option for the pool.
type Option func(*goPool) // WithTaskQueueSize sets the size of the task queue for the pool.
func WithTaskQueueSize(size int) Option {
return func(p *goPool) {
p.taskQueueSize = size
}
}

这样,用户就可以在创建 GoPool 时通过 WithTaskQueueSize 函数来设置任务队列的大小了。例如:

pool := gopool.NewGoPool(100, gopool.WithTaskQueueSize(5000))

--- 到这里结束 ---

GPT-4 给出的第一段代码有接近100行,这就让我犯难了,我能猜到这里面只有不到10行是更新的内容,但是我怎么才能直观地看到这10行修改,然后判断这10行修改是否符合我的预期呢?我需要在100行里找出10行然后将其贴到我原先200多行的源文件中合适的位置,这听起来一点也不酷。

行,今天的故事就从“让这件事变酷”开始。

2. 你需要的背景知识都在这里

容我先介绍下 GoPool 的工作原理以及我想要添加的新功能。

2.1 关于 GoPool 和 DevChat

  1. GoPool 是一个高性能,功能完善且简单易用的 Golang worker pool 库;
  2. DevChat 是一个对接了 GPT-4 的 VS Code 辅助编程插件。

2.2 关于 GoPool 的工作原理

GoPool 大概是这样用的:

package main

import (
"sync"
"time" "github.com/devchat-ai/gopool"
) func main() {
pool := gopool.NewGoPool(100)
defer pool.Release() for i := 0; i < 1000; i++ {
pool.AddTask(func() (interface{}, error){
time.Sleep(10 * time.Millisecond)
return nil, nil
})
}
pool.Wait()
}

也就是说你可以通过 GoPool 来创建一个 worker pool,然后向这个 pool 中添加任务,GoPool 会自动将任务分配给 worker 来执行。

在 GoPool 的源码中有一个 goPool 结构体,其中有2个“队列”,分别是表示 “worker 池”的 workers 和表示“任务队列”的 taskQueue

type goPool struct {
workers []*worker
// ......
// tasks are added to this channel first, then dispatched to workers. Default buffer size is 1 million.
taskQueue chan task
// ......
}

当调用 AddTask() 方法的时候,task 会被先加入到 taskQueue 中,然后被 dispatch() 函数取出并分配给 worker 来执行。

2.3 我想要让 taskQueue 的大小可配置

多数情况下被 AddTask() 方法添加到 taskQueue 中的 task 会被很快取出并分配给 worker 来执行,顺利的话 taskQueue 会被快速“消费”。但是如果 task 的执行时间过长,workers 很繁忙,这时候调用方又一直疯狂地“add task”的话,那么 taskQueue 就会被填满,这时候新添加的 task 就会被阻塞。

当然,阻塞本身并没有大问题,疯狂“add task”除了阻塞也没有其他办法(难道丢弃?似乎阻塞相对更合理一些)。这里的问题是如果 taskQueue 过大,会不会占用过多的内存?举个例子,如果 task 比较复杂,那么当 taskQueue 中有100万个 task 时,那么这100万个 task 就可能会占用过多的内存,这或许不是用户期望的结果。

因此我希望用户可以通过类似 WithTaskQueueSize() 的方式来设置 taskQueue 的大小,这样用户就可以根据自己的需求来灵活排队的 task 的数量了。

3. 用 Diff 视图来看 GPT-4 写的新代码

当你看到这局面的时候,是不是感觉有点迷:

这也是我们通过网页版 ChatGPT 写代码的时候会遇到的困境:怎么知道具体改了那几行?

这时我才发现 DevChat 里的 view diff 功能太好用了:

如上图,点一下“View Diff”按钮,这样就知道了 GPT-4 写的代码具体改了哪些地方了。

你还可以通过这个小箭头选择“不接受”某一处修改:

啥意思呢,就是默认情况下点击 “apply diff” 按钮会应用全部的修改,但是如果你不想应用某一处修改,那么你可以点击这个小箭头。

比如图中的场景,GPT-4 给的代码其实只包含涉及更新的一大段代码,后面还有100行没有给出来,所以直接 “apply diff” 就会导致“后面的100行被删掉”。

所以我们先点击下面这个小箭头,然后再点击 “apply diff” 就可以了:

接着你也可以通过 VS Code 的“Source Control”面板来检查下修改:

4. 通过 Diff 内容让 GPT-4 总结 Commit Message

当代码写完后,就到了最考验人的“commit message”编写环节了。别再“update”一个单词走天下了,让 GPT-4 来帮你写吧:

步骤如下:

  1. 可以用 IDE 里的 Source Control 相关插件来“Stage Changes”,也可以通过 git add 命令来手动添加修改;
  2. 然后在 DevChat 窗口里点击“+”,选择“git diff --cached”,这样就能将当前 diff 内容添加到你和 GPT-4 聊天的“上下文”里;
  3. 在 DevChat 里发送 commit_message 命令,接着就能让 GPT-4 基于当前的 diff 内容来生成 commit message 了。如下图:

最后你可以选择直接在 DevChat 窗口里完成 commit,也可以复制这段 commit message 到其他地方进一步编辑,应用:

BTW:这次我提交的代码是:Add configurable task queue size to GoPool

5. 总结

又到一天总结时,今天我们获得的新技能是:

  1. 通过 DevChat 的“View Diff”功能来查看 GPT-4 写的代码具体改了哪些地方;
  2. 将 “git diff --cached” 内容添加到 GPT-4 聊天上下文,可以让 GPT-4 基于当前的 diff 内容来生成 commit message。

打完收工。

当 GPT-4 拥有了 Diff 视图,那真的是如虎添翼!的更多相关文章

  1. SQL Server 2000 ——系统表和系统视图

    一.系统表 数据字典的详细信息请查SQL SERVER BOL,这里仅列出一部分. 1.1.sysservers 1.查看所有本地服务器及链接服务器 select * from master..sys ...

  2. Java基础之在窗口中绘图——使用模型/视图体系结构在视图中绘图(Sketcher 1 drawing a 3D rectangle)

    控制台程序. 在模型中表示数据视图的类用来显示草图并处理用户的交互操作,所以这种类把显示方法和草图控制器合并在一起.不专用于某个视图的通用GUI创建和操作在SketcherFrame类中处理. 模型对 ...

  3. Cocoa编程中视图控制器与视图类详解

    iPhone编程规则是:一个窗口,多个视图.UIView是iPhone屏幕上很多控件的基础类.每个iPhone用户界面都是由显示在UIWindow(这其实也是个特殊的UIView)内的众多UIView ...

  4. 和iPhone有关的视图控制器:UIViewController、UITabBarController、UINavigationController及其混合用法

    iPhone中的view视图是应用程序对于数据最直观.最直接的呈现方式,如下是我在学习了iPhone中的视图控制器以及由其衍生的特殊子类的总结,希望对那些初学者有所帮助: UIViewControll ...

  5. iOS CoCoa编程中视图控制器与视图类(转)

    分类: iPhone2012-05-28 11:19 837人阅读 评论(0) 收藏 举报 cocoa编程iosuinavigationcontrolleruiviewiphone iPhone编程规 ...

  6. 深入分析MFC文档视图结构(项目实践)

    k_eckel:http://www.mscenter.edu.cn/blog/k_eckel 文档视图结构(Document/View Architecture)是MFC的精髓,也是Observer ...

  7. Vulkan Tutorial 09 图像视图

    操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 使用任何的VkImage,包括在交换链或者渲染管线中的,我们都需要创建VkImage ...

  8. sql server系统表和视图相关的语句

    一.系统表 数据字典的详细信息请查SQL SERVER BOL,这里仅列出一部分. 1.1.sysservers 1.查看所有本地服务器及链接服务器 select * from master..sys ...

  9. vue 中 命名视图的用法

    今天主要记录  vue中命名视图的用法 先奉上官网网址:https://router.vuejs.org/zh/guide/essentials/named-views.html 一般情况下,一个页面 ...

  10. Vulkan Tutorial 09 图像与视图

    操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 使用任何的VkImage,包括在交换链或者渲染管线中的,我们都需要创建VkImage ...

随机推荐

  1. 2022-06-17:给定一个数组arr,含有n个数字,可能有正、有负、有0, 给定一个正数k。 返回所有子序列中,累加和最大的前k个子序列累加和。 假设K不大,怎么算最快? 来自Amazon。

    2022-06-17:给定一个数组arr,含有n个数字,可能有正.有负.有0, 给定一个正数k. 返回所有子序列中,累加和最大的前k个子序列累加和. 假设K不大,怎么算最快? 来自Amazon. 答案 ...

  2. 2021-06-27:给定一个正数数组arr,代表若干人的体重。再给定一个正数limit,表示所有船共同拥有的载重量。每艘船最多坐两人,且不能超过载重,想让所有的人同时过河,并且用最好的分配方法让船尽

    2021-06-27:给定一个正数数组arr,代表若干人的体重.再给定一个正数limit,表示所有船共同拥有的载重量.每艘船最多坐两人,且不能超过载重,想让所有的人同时过河,并且用最好的分配方法让船尽 ...

  3. reverse逆转,即反向排序

    reverse逆转,即反向排序 print(Student.objects.all().exclude(nickname='A').reverse()

  4. Redis内存兜底策略——内存淘汰及回收机制

    Redis内存兜底策略--内存淘汰及回收机制 Redis内存淘汰及回收策略都是Redis内存优化兜底的策略,那它们是如何进行兜底的呢?先来说明一下什么是内存淘汰和内存回收策略: Redis内存淘汰:当 ...

  5. 第一单元 .Net 平台介绍

    第一单元 .Net 平台介绍 学习编程,电脑基本配置(当然配置越高越好): 内存 :初期学习8 G,后期可能跟不上, 最好16 G以上 硬盘:500 G,5400 转速,至少C盘是固态,全是固态最好 ...

  6. 图解MySQL在Linux下的安装与配置

    MySQL简介 MySQL是最流行的RDBMS(Relational Database Management System:关系数据库管理系统)之一,被广泛地应用在互联网上的中小型网站中.关联数据库将 ...

  7. StampedLock:高并发场景下一种比读写锁更快的锁

    摘要:在读多写少的环境中,有没有一种比ReadWriteLock更快的锁呢?有,那就是JDK1.8中新增的StampedLock! 本文分享自华为云社区<[高并发]高并发场景下一种比读写锁更快的 ...

  8. Oracle Linux切换uek内核到rhck内核解决ACFS兼容问题

    背景:协助客户做验证,客户使用的是RHEL7.6环境,我这边是OEL7.6环境,开始以为区别不大,结果acfs兼容还是遇到问题,特此记录下. 现象:asmca图形没有acfs相关内容,无法使用acfs ...

  9. VLAN——提高网络性能、安全性和灵活性的利器

    前言 VLAN是Virtual Local Area Network的缩写,它是一种通过网络交换机虚拟划分局域网的技术.VLAN可以将一个物理局域网划分成多个逻辑上的虚拟局域网,各个虚拟局域网之间相互 ...

  10. 从0搭建Vue3组件库(十):如何搭建一个 Cli 脚手架

    本篇文章将实现一个名为create-easyest脚手架的开发,只需一个命令npm init easyest就可以将整个组件库开发框架拉到本地. 创建 Cli 包 首先,我们在 packages 目录 ...