You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: ctr.go
    path of file: ./repos/podman/pkg/parallel/ctr
    
    the code of the file until where you have to start completion: //go:build !remote

package ctr

import (
	"context"

	"github.com/containers/podman/v5/libpod"
	"github.com/containers/podman/v5/pkg/parallel"
	"github.com/sirupsen/logrus"
)

// ContainerOp performs the given function on the given set of
// containers, using a number of parallel threads.
// If no error is returned, each container specified in ctrs will have an entry
// in the resulting map; containers with no error will be set to nil.
func ContainerOp(ctx context.Context, ctrs []*libpod.Container, applyFunc func(*libpod.Container) error) (map[*libpod.Container]error, error) {
	// We could use a sync.Map but given Go's lack of generic I'd rather
	// just use a lock on a normal map...
	// The expectation is that most o
    
func ContainerOp(ctx context.Context, ctrs []*libpod.Container, applyFunc func(*libpod.Container) error) (map[*libpod.Container]error, error) {
	// We could use a sync.Map but given Go's lack of generic I'd rather
	// just use a lock on a normal map...
	// The expectation is that most of the time is spent in applyFunc
	// anyways.
	var (
		errMap = make(map[*libpod.Container]<-chan error)
	)

	for _, ctr := range ctrs {
		c := ctr
		logrus.Debugf("Starting parallel job on container %s", c.ID())
		errChan := parallel.Enqueue(ctx, func() error {
			return applyFunc(c)
		})
		errMap[c] = errChan
	}

	finalErr := make(map[*libpod.Container]error)
	for ctr, errChan := range errMap {
		err := <-errChan
		finalErr[ctr] = err
	}

	return finalErr, nil
}