🧠Почему context.WithCancel может вызвать утечку goroutine
context.WithCancel — удобный способ завершать операции, но если не вызывать cancel(), вы получите утечку. Причём не всегда это очевидно.
Посмотрим:
func handler(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithCancel(r.Context()) // cancel не вызывается! go doSomething(ctx) w.Write([]byte("done")) }
func doSomething(ctx context.Context) { select { case <-time.After(10 * time.Second): fmt.Println("done work") case <-ctx.Done(): fmt.Println("canceled") } }
Что здесь не так?
Если handler завершится раньше, чем doSomething, и cancel() не вызван — doSomething останется висеть, пока не истечёт r.Context()илиtime.After. И таких горутин может накопиться много, особенно при высоких нагрузках.
💡 Как избежать
1. Всегда вызывай cancel(), когда используешь context.WithCancel, даже если кажется, что это «не нужно».
2. Если передаёшь контекст в goroutine — убедись, что она завершится, даже если вызывающая функция ушла.
context.WithCancel — мощный инструмент. Но без вызова cancel() ты легко создашь утечку, которую не поймаешь ни в логах, ни в профилях — только под нагрузкой.
🧠Почему context.WithCancel может вызвать утечку goroutine
context.WithCancel — удобный способ завершать операции, но если не вызывать cancel(), вы получите утечку. Причём не всегда это очевидно.
Посмотрим:
func handler(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithCancel(r.Context()) // cancel не вызывается! go doSomething(ctx) w.Write([]byte("done")) }
func doSomething(ctx context.Context) { select { case <-time.After(10 * time.Second): fmt.Println("done work") case <-ctx.Done(): fmt.Println("canceled") } }
Что здесь не так?
Если handler завершится раньше, чем doSomething, и cancel() не вызван — doSomething останется висеть, пока не истечёт r.Context()илиtime.After. И таких горутин может накопиться много, особенно при высоких нагрузках.
💡 Как избежать
1. Всегда вызывай cancel(), когда используешь context.WithCancel, даже если кажется, что это «не нужно».
2. Если передаёшь контекст в goroutine — убедись, что она завершится, даже если вызывающая функция ушла.
context.WithCancel — мощный инструмент. Но без вызова cancel() ты легко создашь утечку, которую не поймаешь ни в логах, ни в профилях — только под нагрузкой.
Mr. Durov launched Telegram in late 2013 with his brother, Nikolai, just months before he was pushed out of VK, the Russian social-media platform he founded. Mr. Durov pitched his new app—funded with the proceeds from the VK sale—less as a business than as a way for people to send messages while avoiding government surveillance and censorship.
How Does Bitcoin Work?
Bitcoin is built on a distributed digital record called a blockchain. As the name implies, blockchain is a linked body of data, made up of units called blocks that contain information about each and every transaction, including date and time, total value, buyer and seller, and a unique identifying code for each exchange. Entries are strung together in chronological order, creating a digital chain of blocks. “Once a block is added to the blockchain, it becomes accessible to anyone who wishes to view it, acting as a public ledger of cryptocurrency transactions,” says Stacey Harris, consultant for Pelicoin, a network of cryptocurrency ATMs. Blockchain is decentralized, which means it’s not controlled by any one organization. “It’s like a Google Doc that anyone can work on,” says Buchi Okoro, CEO and co-founder of African cryptocurrency exchange Quidax. “Nobody owns it, but anyone who has a link can contribute to it. And as different people update it, your copy also gets updated.”