go 语言 goroutine 与 主 goroutine 的代码的先行性问题。

demon_li · 2021-06-26 17:46:04 · 3523 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2021-06-26 17:46:04 的主题,其中的信息可能已经有所发展或是发生改变。

本人新学Go语言,有个问题一直没找到相关资料,请高手帮忙解答以下。

在Java中,多个线程之间,只有保证了 先行性问题,才能保证不同线程的代码是按预期的先后顺序执行

以下是示例代码:

package main
import (
    "fmt"
)
func main() {
    // 构建一个通道
    ch := make(chan int)
    // 开启一个并发匿名函数
    go func() {
        fmt.Println("start goroutine")     //1
        // 通过通道通知main的goroutine
        ch <- 0
        fmt.Println("exit goroutine")      //2
    }()
    fmt.Println("wait goroutine")          //3
    // 等待匿名goroutine
    <-ch
    fmt.Println("all done")                //4
}

输出结果: 执行了多次一直是这个结果,与java学到的线程相关知识不匹配。

wait goroutine
start goroutine
exit goroutine
all done

为什么 1和3 不是随机出现的, 2和4 不是随机出现的。 1和3 是2个不同goroutine,不是应该不能保证哪行代码先执行吗。


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3523 次点击  
加入收藏 微博
7 回复  |  直到 2021-06-28 11:31:21
focusonline
focusonline · #1 · 4年之前

我觉得你啊可能对线程有一些误解.java的线程也不是你想的那样.你得到这个结果一点都不奇怪. 当前执行的线程或者协程是不会马上放弃CPU给其他线程和线程的除非使用了相关的语句和遇到了可以放弃CPU的情况, 你的例子就是这种情况.

demon_li
demon_li · #2 · 4年之前

package demon.research;

public class BefortTest {

public static  Object lock = new Object();
public static void main(String[] args) {

    try{
        Thread t  = new Thread(new Runnable() {
            @Override
            public void run() {

                System.out.println("start");
                synchronized (lock)
                {
                    lock.notifyAll();
                }


                System.out.println("end");
            }
        });

        t.start();

        System.out.println("wait");
        synchronized (lock)
        {
            lock.wait();
        }

        System.out.println("end all");
    }
    catch (Exception ex)
    {

    }


}

}

打印结果出现以下结果:

wait start end all end

所以Java 代码一定有先行性的考虑,你的解释是不正确的。

zzustu
zzustu · #3 · 4年之前

理想情况下是1和3先后顺序随机。实际情况是启动一个goroutine或Thread需要消耗资源,所以一般都是 3 早于 1 先打印出来。 还有就是 go 的输出顺序是 3124 Java也是 3124。你又说不一样,

focusonline
focusonline · #4 · 4年之前
demon_lidemon_li #2 回复

package demon.research; public class BefortTest { public static Object lock = new Object(); public static void main(String[] args) { try{ Thread t = new Thread(new Runnable() { @Override public void run() { System.out.println("start"); synchronized (lock) { lock.notifyAll(); } System.out.println("end"); } }); t.start(); System.out.println("wait"); synchronized (lock) { lock.wait(); } System.out.println("end all"); } catch (Exception ex) { } } } 打印结果出现以下结果: wait start end all end 所以Java 代码一定有先行性的考虑,你的解释是不正确的。

亲, 你这个java代码和go的不一样的, go的channel和java的lock实现也不一样, 其实原因我已经说过了, #3 楼的同学应该是理解了. 当前线程或者协程需要等一个点才能放弃对CPU的占用调度给其他的线程或者协程. 而且线程和协程创建了也不会马上启动的, 也是在队列中需要这么个点才能得到CPU的执行机会的.

jarlyyn
jarlyyn · #5 · 4年之前
demon_lidemon_li #2 回复

package demon.research; public class BefortTest { public static Object lock = new Object(); public static void main(String[] args) { try{ Thread t = new Thread(new Runnable() { @Override public void run() { System.out.println("start"); synchronized (lock) { lock.notifyAll(); } System.out.println("end"); } }); t.start(); System.out.println("wait"); synchronized (lock) { lock.wait(); } System.out.println("end all"); } catch (Exception ex) { } } } 打印结果出现以下结果: wait start end all end 所以Java 代码一定有先行性的考虑,你的解释是不正确的。

如果你需要lock,就直接用lock

chan不是用来解决这个问题的……

demon_li
demon_li · #6 · 4年之前

@zzustu 问题已知晓。我本地调试了很多遍,没有出现乱序,让其他人调试,出现了乱序,是预期的,所以go routine 也是不能保证顺序。我本意也是go 应该出现乱序。

demon_li
demon_li · #7 · 4年之前

@jarlyyn 不是想用了lock,只是本地测试的时候,没有出现乱序,所以有些疑问。我的理解是go 应该出现乱序。

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传