【问题标题】:Hello, Im studying fyne.io for golang and I faced a problem你好,我正在为 golang 学习 fyne.io,我遇到了一个问题
【发布时间】:2021-03-31 19:55:29
【问题描述】:

我正在为 golang 学习 fyne.io,我遇到了一个问题。我做了一个最小的仪表板交互任务,应该同时开始,问题是用户必须有权随时停止任何任务。我决定使用通道来发送任务和上下文来停止任务,但这不起作用,我的意思是当任务到达通道时,worker(task *Task) 开始,我点击停止,当这种情况发生时,startTask(task *Task) 停止工作,但@987654324 @不停。怎么了?我做错了吗?

Exmaple running

package main

import (
    "context"
    "fmt"
    "fyne.io/fyne/v2"
    "fyne.io/fyne/v2/app"
    "fyne.io/fyne/v2/container"
    "fyne.io/fyne/v2/theme"
    "fyne.io/fyne/v2/widget"
    "github.com/k0kubun/pp"
    "time"
)

type Task struct {
    ID          int
    Chancel     context.CancelFunc
}

var channelTask chan *Task

func worker(task *Task)  {
    for i := 0; i < 10; i ++ {
        fmt.Println(fmt.Sprintf("Task ID: %d running...%d", task.ID, i))
        time.Sleep(1 * time.Second)
    }
}

func startTask(task *Task) {
    go func() {
        ctx, cancel := context.WithCancel(context.Background())
        for {
            select {
            case <- ctx.Done():
                pp.Println(fmt.Sprintf("Task ID: %d stopped!", task.ID))
                return
            case task := <-channelTask:
                task.Chancel = cancel
                fmt.Println(fmt.Sprintf("Task ID: %d stared!", task.ID))
                go func() {
                    worker(task)
                }()
            default:
                continue
            }
        }
    }()
}

func main()  {
    a := app.New()
    w := a.NewWindow("Testing")
    channelTask = make(chan *Task)
    w.SetContent(createList())
    w.CenterOnScreen()
    w.Resize(fyne.Size{
        Width:  500,
        Height: 300,
    })
    w.SetFixedSize(true)
    w.ShowAndRun()
}

func createList() *widget.List {
    tasks := createTasks()
    return widget.NewList(
        func() int {
            return len(tasks)
        },
        func() fyne.CanvasObject {
            return container.NewGridWithColumns(3,
                widget.NewLabel(""),
                widget.NewButtonWithIcon("Run", theme.MediaPlayIcon(), func() {}),
                widget.NewButtonWithIcon("Stop", theme.MediaStopIcon(), func() {}),
            )
        },
        func(id widget.ListItemID, item fyne.CanvasObject) {
            task := tasks[id]
            item.(*fyne.Container).Objects[0].(*widget.Label).SetText(fmt.Sprintf("Task ID: %d", task.ID))
            buttonRun := item.(*fyne.Container).Objects[1].(*widget.Button)
            buttonStop := item.(*fyne.Container).Objects[2].(*widget.Button)
            buttonStop.Disable()
            buttonRun.OnTapped = func() {
                fmt.Println(fmt.Sprintf("Task ID: %d Start button pushed.", task.ID))
                startTask(task)
                buttonRun.Disable()
                buttonStop.Enable()
                channelTask <- task
                return
            }
            buttonStop.OnTapped = func() {
                fmt.Println(fmt.Sprintf("Task ID: %d Stop button pushed.", task.ID))
                task.Chancel()
                buttonRun.Enable()
                return
            }},
    )
}

func createTasks() []*Task {
    var tasks []*Task
    for i := 0; i < 5; i ++ {
        tasks = append(tasks, &Task{ID: i})
    }
    return tasks
}

【问题讨论】:

    标签: go concurrency


    【解决方案1】:

    您的worker 未检查Task 是否已取消。 我建议将Context 传递给工作人员,以便您查看是否完成。

    【讨论】:

    • 如果我将上下文传递给 worker 并检查取消,那么我的算法会阻塞循环并仅在算法执行后检查取消。我需要根据我的要求停止算法。 - prnt.sc/1112b63
    • 您不应该将等待代码移动到工作程序中,这会阻塞。而是使用上下文来询问,也许是每次迭代,它是否被取消。见stackoverflow.com/questions/47179024/…
    • 哦,我明白你的意思。这实际上对我有用 - link。但问题仍然存在。如果我有一个很长的算法link,我是否必须在每个逻辑块中检查它以进行撤消?真的不能一招打断整个功能吗?无论如何,谢谢!
    • 我不知道有任何方式可以在一般意义上“只是中断”代码。任何可以取消的代码都需要自己处理,以便干净地完成退出。
    猜你喜欢
    • 2022-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-24
    • 1970-01-01
    • 2021-05-28
    • 2022-01-11
    • 2013-10-08
    相关资源
    最近更新 更多