取消用户特定的 goroutines
Cancelling user specific goroutines
我有一个应用程序(网络应用程序)可以让用户使用 twitter oauth 登录并提供自动删除推文的功能。在用户登录到网络应用程序后,我将为每个将删除用户推文列表的用户启动一个 goroutines(通过 REST api)。
假设有 100 个用户,每个用户有 500++ 条推文:
如何在删除过程中停止删除go例程。
例如:用户 30 在启动删除过程 2 分钟后请求停止删除推文(这应该通过 API 调用我的应用程序来完成)。
- 考虑到 http 请求和 twitter API 限制,为了最大限度地提高应用程序的性能,创建 go 例程的最佳做法是什么。我应该为每个用户创建 go 例程还是实施工作池?
信息:我正在使用 anaconda 作为 Twitter 客户端后端
编辑:
我找到了一种使用带上下文的地图来实现此功能的方法。这是供参考的代码。感谢 https://gist.github.com/montanaflynn/020e75c6605dbe2c726e410020a7a974
package main
import (
"context"
"fmt"
"log"
"net/http"
"sync"
"time"
)
// a concurrent safe map type by embedding sync.Mutex
type cancelMap struct {
sync.Mutex
internal map[string]context.CancelFunc
}
func newCancelMap() *cancelMap {
return &cancelMap{
internal: make(map[string]context.CancelFunc),
}
}
func (c *cancelMap) Get(key string) (value context.CancelFunc, ok bool) {
c.Lock()
result, ok := c.internal[key]
c.Unlock()
return result, ok
}
func (c *cancelMap) Set(key string, value context.CancelFunc) {
c.Lock()
c.internal[key] = value
c.Unlock()
}
func (c *cancelMap) Delete(key string) {
c.Lock()
delete(c.internal, key)
c.Unlock()
}
// create global jobs map with cancel function
var jobs = newCancelMap()
// the pretend worker will be wrapped here
// https://siadat.github.io/post/context
func work(ctx context.Context, id string) {
for {
select {
case <-ctx.Done():
fmt.Printf("Cancelling job id %s\n", id)
return
case <-time.After(time.Second):
fmt.Printf("Doing job id %s\n", id)
}
}
}
func startHandler(w http.ResponseWriter, r *http.Request) {
// get job id and name from query parameters
id := r.URL.Query().Get("id")
// check if job already exists in jobs map
if _, ok := jobs.Get(id); ok {
fmt.Fprintf(w, "Already started job id: %s\n", id)
return
}
// create new context with cancel for the job
ctx, cancel := context.WithCancel(context.Background())
// save it in the global map of jobs
jobs.Set(id, cancel)
// actually start running the job
go work(ctx, id)
// return 200 with message
fmt.Fprintf(w, "Job id: %s has been started\n", id)
}
func stopHandler(w http.ResponseWriter, r *http.Request) {
// get job id and name from query parameters
id := r.URL.Query().Get("id")
// check for cancel func from jobs map
cancel, found := jobs.Get(id)
if !found {
fmt.Fprintf(w, "Job id: %s is not running\n", id)
return
}
// cancel the jobs
cancel()
// delete job from jobs map
jobs.Delete(id)
// return 200 with message
fmt.Fprintf(w, "Job id: %s has been canceled\n", id)
}
func main() {
http.HandleFunc("/start", startHandler)
http.HandleFunc("/stop", stopHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
你不能从外部停止goroutine,goroutine必须支持取消操作。详情参见:. Common means to support cancellation is channels and the context
包。
至于哪个更适合你,范围太广了。这取决于很多事情,但作为示例/参考,标准库的 HTTP 服务器在其自己的 goroutine 中为每个传入的 HTTP 请求提供服务,并且具有不错的性能。
如果请求率很高,可能值得创建和使用 goroutine 池(或使用执行此操作的第 3 方库/路由器),但这实际上取决于您的实际代码,您应该测量/配置文件您的应用程序来决定它是否需要或是否值得。
通常我们可以说,如果每个 goroutine 所做的工作与创建/调度 goroutine 所需的开销相比是 "big",那么为其使用一个新的 goroutine 通常会更干净。在诸如 Twitter API 之类的 goroutine 中访问第三方服务可能比启动 goroutine 的工作量和延迟多几个数量级,因此您应该可以为每个 goroutine 启动一个 goroutine(没有性能损失)。
how do I stop [...] go routines
你用例如启动goroutine一个完成的频道,一旦完成的频道关闭,你就停止你的 goroutine。
what is the best practices of creating go routines in order to maximize the performance of the apps considering the http request and twitter API limit
这个问题太宽泛了。
我有一个应用程序(网络应用程序)可以让用户使用 twitter oauth 登录并提供自动删除推文的功能。在用户登录到网络应用程序后,我将为每个将删除用户推文列表的用户启动一个 goroutines(通过 REST api)。
假设有 100 个用户,每个用户有 500++ 条推文:
如何在删除过程中停止删除go例程。
例如:用户 30 在启动删除过程 2 分钟后请求停止删除推文(这应该通过 API 调用我的应用程序来完成)。
- 考虑到 http 请求和 twitter API 限制,为了最大限度地提高应用程序的性能,创建 go 例程的最佳做法是什么。我应该为每个用户创建 go 例程还是实施工作池?
信息:我正在使用 anaconda 作为 Twitter 客户端后端
编辑:
我找到了一种使用带上下文的地图来实现此功能的方法。这是供参考的代码。感谢 https://gist.github.com/montanaflynn/020e75c6605dbe2c726e410020a7a974
package main
import (
"context"
"fmt"
"log"
"net/http"
"sync"
"time"
)
// a concurrent safe map type by embedding sync.Mutex
type cancelMap struct {
sync.Mutex
internal map[string]context.CancelFunc
}
func newCancelMap() *cancelMap {
return &cancelMap{
internal: make(map[string]context.CancelFunc),
}
}
func (c *cancelMap) Get(key string) (value context.CancelFunc, ok bool) {
c.Lock()
result, ok := c.internal[key]
c.Unlock()
return result, ok
}
func (c *cancelMap) Set(key string, value context.CancelFunc) {
c.Lock()
c.internal[key] = value
c.Unlock()
}
func (c *cancelMap) Delete(key string) {
c.Lock()
delete(c.internal, key)
c.Unlock()
}
// create global jobs map with cancel function
var jobs = newCancelMap()
// the pretend worker will be wrapped here
// https://siadat.github.io/post/context
func work(ctx context.Context, id string) {
for {
select {
case <-ctx.Done():
fmt.Printf("Cancelling job id %s\n", id)
return
case <-time.After(time.Second):
fmt.Printf("Doing job id %s\n", id)
}
}
}
func startHandler(w http.ResponseWriter, r *http.Request) {
// get job id and name from query parameters
id := r.URL.Query().Get("id")
// check if job already exists in jobs map
if _, ok := jobs.Get(id); ok {
fmt.Fprintf(w, "Already started job id: %s\n", id)
return
}
// create new context with cancel for the job
ctx, cancel := context.WithCancel(context.Background())
// save it in the global map of jobs
jobs.Set(id, cancel)
// actually start running the job
go work(ctx, id)
// return 200 with message
fmt.Fprintf(w, "Job id: %s has been started\n", id)
}
func stopHandler(w http.ResponseWriter, r *http.Request) {
// get job id and name from query parameters
id := r.URL.Query().Get("id")
// check for cancel func from jobs map
cancel, found := jobs.Get(id)
if !found {
fmt.Fprintf(w, "Job id: %s is not running\n", id)
return
}
// cancel the jobs
cancel()
// delete job from jobs map
jobs.Delete(id)
// return 200 with message
fmt.Fprintf(w, "Job id: %s has been canceled\n", id)
}
func main() {
http.HandleFunc("/start", startHandler)
http.HandleFunc("/stop", stopHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
你不能从外部停止goroutine,goroutine必须支持取消操作。详情参见:context
包。
至于哪个更适合你,范围太广了。这取决于很多事情,但作为示例/参考,标准库的 HTTP 服务器在其自己的 goroutine 中为每个传入的 HTTP 请求提供服务,并且具有不错的性能。
如果请求率很高,可能值得创建和使用 goroutine 池(或使用执行此操作的第 3 方库/路由器),但这实际上取决于您的实际代码,您应该测量/配置文件您的应用程序来决定它是否需要或是否值得。
通常我们可以说,如果每个 goroutine 所做的工作与创建/调度 goroutine 所需的开销相比是 "big",那么为其使用一个新的 goroutine 通常会更干净。在诸如 Twitter API 之类的 goroutine 中访问第三方服务可能比启动 goroutine 的工作量和延迟多几个数量级,因此您应该可以为每个 goroutine 启动一个 goroutine(没有性能损失)。
how do I stop [...] go routines
你用例如启动goroutine一个完成的频道,一旦完成的频道关闭,你就停止你的 goroutine。
what is the best practices of creating go routines in order to maximize the performance of the apps considering the http request and twitter API limit
这个问题太宽泛了。