По всем вопросам- @haarrp
@itchannels_telegram - 🔥полезные ит-каналы
https://t.me/Golang_google - Golang программирование
@golangl - golang chat
@GolangJobsit - golang channel jobs
@golang_jobsgo - go chat jobs
Post #843
2.36K

GO @golangtests
Showing posts older than #844 · Back to latest


package main
import "errors"
type MyError struct{}
func (MyError) Error() string { return "" }
func main() {
var me = MyError{}
var se = errors.New("foo")
println(errors.As(me, &se))
}
package main
import (
"context"
"errors"
"fmt"
"math/rand"
"sync"
"time"
)
type job[T any] struct {
i int
val T
}
func Process[T any, R any](
parent context.Context,
in []T,
worker func(context.Context, T) (R, error),
parallelism int,
) ([]R, error) {
if parallelism <= 0 {
return nil, errors.New("parallelism must be > 0")
}
ctx, cancel := context.WithCancelCause(parent)
defer cancel(nil)
jobs := make(chan job[T], parallelism) // лёгкая обратная давление
out := make([]R, len(in))
var wg sync.WaitGroup
var once sync.Once
var firstErr error
// Рабочие
workerFn := func() {
defer wg.Done()
for {
select {
case <-ctx.Done():
return
case j, ok := <-jobs:
if !ok {
return
}
res, err := worker(ctx, j.val)
if err != nil {
once.Do(func() {
firstErr = err
cancel(err) // прерываем остальных
})
return
}
// Сохраняем порядок
out[j.i] = res
}
}
}
// Старт пула
wg.Add(parallelism)
for k := 0; k < parallelism; k++ {
go workerFn()
}
// Диспетчер задач
sendLoop:
for i, v := range in {
select {
case <-ctx.Done():
break sendLoop
case jobs <- job[T]{i: i, val: v}:
}
}
close(jobs)
// Ждём завершения
wg.Wait()
// Если была отмена по ошибке — вернём её
if firstErr != nil {
return nil, firstErr
}
// Если отменил родительский контекст — вернём его причину
if err := context.Cause(ctx); err != nil && !errors.Is(err, context.Canceled) && !errors.Is(err, context.DeadlineExceeded) {
// это cause из cancel(err), уже обработали выше
} else if err := context.Cause(parent); err != nil {
return nil, err
}
return out, nil
}
// Демонстрация: умножаем числа с случайной задержкой; каждое третье число — ошибка.
// Видно, что вывод упорядочен по входу, а отмена срабатывает на первой ошибке.
func main() {
rand.New(rand.NewSource(time.Now().UnixNano()))
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
input := []int{1, 2, 3, 4, 5, 6, 7}
parallelism := 3
worker := func(ctx context.Context, x int) (int, error) {
// эмуляция непредсказуемого времени работы
time.Sleep(time.Duration(rand.Intn(120)) * time.Millisecond)
if x%7 == 0 { // попробуй поменять условие на (x%3==0), чтобы увидеть раннюю отмену
return 0, fmt.Errorf("bad luck on %d", x)
}
select {
case <-ctx.Done():
return 0, ctx.Err()
default:
return x * x, nil
}
}
res, err := Process[int, int](ctx, input, worker, parallelism)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("results:", res)
}


Forwarded from Golang вопросы собеседований
package main
import "fmt"
func main() {
s := make([]int, 3, 4) // Длина 3, capacity 4
s[0], s[1], s[2] = 1, 2, 3
modifySlice(s)
fmt.Println(s)
}
func modifySlice(s []int) {
s = append(s, 4)
s[0] = 100
}
[1 2 3] [100 2 3] [1 2 3 4] [100 2 3 4]

Forwarded from Golang



package main
import (
"fmt"
)
func tricky() (err error) {
defer func() {
fmt.Println("D1:", err) // состояние именованного результата до recover
if r := recover(); r != nil {
err = fmt.Errorf("recovered: %v", r)
}
fmt.Println("D2:", err) // состояние после recover
}()
defer func() {
panic(2) // паника №2 во время размотки стека
}()
panic(1) // паника №1
}
func main() {
fmt.Println("start")
fmt.Println("ret:", tricky())
fmt.Println("end")
}


_test.go — например, sum_test.go testing и напиши функцию вида: TestXxx(t *testing.T) go test