V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iOS 开发实用技术导航
NSHipster 中文版
http://nshipster.cn/
cocos2d 开源 2D 游戏引擎
http://www.cocos2d-iphone.org/
CocoaPods
http://cocoapods.org/
Google Analytics for Mobile 统计解决方案
http://code.google.com/mobile/analytics/
WWDC
https://developer.apple.com/wwdc/
Design Guides and Resources
https://developer.apple.com/design/
Transcripts of WWDC sessions
http://asciiwwdc.com
Cocoa with Love
http://cocoawithlove.com/
Cocoa Dev Central
http://cocoadevcentral.com/
NSHipster
http://nshipster.com/
Style Guides
Google Objective-C Style Guide
NYTimes Objective-C Style Guide
Useful Tools and Services
Charles Web Debugging Proxy
Smore
chipmuck
V2EX  ›  iDev

两个问题。多线程操作 UI 为什么不可行?为什么 UI 线程必为主线程?

  •  
  •   chipmuck · 2018-01-03 16:02:04 +08:00 · 9086 次点击
    这是一个创建于 2547 天前的主题,其中的信息可能已经有所发展或是发生改变。

    第二个问题我解释一下,意思就是:大多数程序语言都把 UI 线程定在主线程上,那为什么不能将 UI 单独拿出来放到一个独立的子线程上进行操作?其中有啥玄学呢?

    第 1 条附言  ·  2018-01-04 10:12:09 +08:00
    感谢大家的回答,这里做一个总结,主要面向第二个问题:

    1、远古时代单线程环境下,所有的逻辑都只能放在进程中的主线程中;

    2、多线程中,因为可能部分操作(如网络请求、IO、或其他操作)在应用中不是必要的,所以可以将它们置于子线程处理。而 UI 操作需要经常进行,所以将它放置于主线程。

    3、线程之间的上下文切换需要耗费一些性能,而像 UI 这类频繁触发的操作,程序没有必要也不应该为它浪费这些额外的开销。为了节约成本并提高性能,所以将 UI 置于主线程。

    以上主要根据 Cocoa 开发的经验角度来进行总结,如有误,请指正。
    24 条回复    2018-01-09 17:58:36 +08:00
    gesse
        1
    gesse  
       2018-01-03 16:08:29 +08:00   ❤️ 1
    UI 当然要用单线程,多线程操作你想让 UI 在同一时刻呈现不同的样子?

    至于为什么放主线程,感觉应该是主线程按理说应该更加不容易『卡死』,让你把复杂数据、网络等操作放到子线程,『默默』处理好了以后,把结果呈现给 UI 就可以了。
    InternetExplorer
        2
    InternetExplorer  
       2018-01-03 16:15:11 +08:00   ❤️ 1
    多线程操作 UI 会导致 UI 进入叠加态,人作为观察者观察 UI 则会使 UI 坍缩到某一具体的形态,为了避免这种不确定性,所以只用一个线程操作 UI (雾
    TestSmirk
        3
    TestSmirk  
       2018-01-03 16:17:30 +08:00   ❤️ 1
    多线程操作 UI emmm,你见过 gif 图吧..
    piaochen0
        4
    piaochen0  
       2018-01-03 16:19:06 +08:00   ❤️ 1
    在一般的 UI 系统中,UI 的生成,渲染永远运行在主线程中的...其他线程和主线程是平行状态...
    chipmuck
        5
    chipmuck  
    OP
       2018-01-03 16:22:50 +08:00
    @piaochen0 这是系统设计的原因吗?
    chipmuck
        6
    chipmuck  
    OP
       2018-01-03 16:24:06 +08:00
    @InternetExplorer
    @TestSmirk

    多线程操作 UI 的问题没啥疑问的,关键是第二个问题。。
    alqaz
        7
    alqaz  
       2018-01-03 16:32:12 +08:00   ❤️ 1
    在很久以前,没有多线程,可能是为了兼容性;还有,别人不想用多线程的情况下那怎么难道系统还要默认额外开一个线程给它?瞎猜的。
    deadEgg
        8
    deadEgg  
       2018-01-03 16:34:47 +08:00   ❤️ 1
    回答第二个问题:

    当有子线程,主线程和子线程地位相同,不会因为主线程死亡而进程死亡

    猜测 ui 线程放到主线程有两个原因:
    1. ui 初始化做的工作比较多,如果不是主线程,启动子线程需要资源和时间,ui 启动慢
    2. 更新 ui 需要在 ui 线程,如果非主线程那你每次更新 ui 都要进行线程通信( android 为例,setXXX 就要通信一次,速度堪忧)

    主要想到这两个原因,望指正
    piaochen0
        9
    piaochen0  
       2018-01-03 16:41:38 +08:00   ❤️ 1
    我的理解是,
    1.作为一个有界面的系统,最基本解决的问题是:UI,用户的输入。假如是你自己从最底层来设计这套系统,是不是考虑在主线程运行优先级最高的选项?两者属于比较底层和基础的功能。而且确实也没太必要引入其他线程,毕竟线程引入也需要开销。更何况,很多系统或者系统的早期,也不支持多线程,或者支持的不太好。
    2.UI 的渲染在某些软硬件系统中,其实是资源消耗很严重的操作,假如任用多个线程随意操作,会很影响性能吧。
    nybux
        10
    nybux  
       2018-01-03 16:44:54 +08:00   ❤️ 3
    其实核心的问题是消息循环,对于直接涉及到底层的语言,是可以的,windows 程序,gtk,完全可以把消息循环放在其他线程里面。甚至 UI 操作不要求一定要在特定线程里面。但是一旦涉及到框架。比如 MFC/QT/SWT。为了使用方便,不阻塞 UI,避免让使用者了解过多的线程细接。所以,就把 ui 操作强制放到某个线程中了。
    am241
        11
    am241  
       2018-01-03 16:48:09 +08:00 via Android   ❤️ 1
    ui 和游戏有点像,输入 计算 渲染的循环
    whileFalse
        12
    whileFalse  
       2018-01-03 16:52:06 +08:00   ❤️ 2
    UI 当然可以是子线程。主线程还是子线程主要看模型。

    对于 iOS 开发来说,UI 是主要的,后台线程是为了加速 UI 线程的响应速度存在的。可以没有后台线程,不能没有 UI 线程。所以 UI 是主线程。
    如果你用 python 写 UI,情况就翻过来了。python 主线程是个命令行,命令行线程再创建 UI 线程。命令行线程没有 UI 也能跑,UI 却不得不依附命令行线程。所以 UI 是子线程。
    mooncakejs
        13
    mooncakejs  
       2018-01-03 16:52:27 +08:00   ❤️ 1
    UI 不是不可以多线程,而是多线程不可控,所以搞个单线程模型简单一点。
    crysislinux
        14
    crysislinux  
       2018-01-03 16:54:30 +08:00 via Android   ❤️ 1
    第二个问题,实际上很多程序是没有用多线程的,但是它们却有 gui,此时只有一个主线程,当然 ui 线程就是主线程了。所以当有多线程的时候,反正 ui 要一个线程,为何不统一用主线程呢?
    momocraft
        15
    momocraft  
       2018-01-03 17:02:24 +08:00   ❤️ 1
    1 可能是因為多線程時的內存可見性問題
    2 有沒有可能是人們把默認創建的給 ui 用的線程 (而不是進程初始的那個) 稱做主線程?
    zhuangzhuang1988
        16
    zhuangzhuang1988  
       2018-01-03 17:02:38 +08:00   ❤️ 1
    第二个问题不是得比如
    F#的 fsi,支持 Form 渲染,而这个 UI 线程不是主线程
    shibo501c
        17
    shibo501c  
       2018-01-03 17:17:52 +08:00   ❤️ 1
    之前也疑惑过,多线程开发难度大,容易死锁,Java 并发编程第 9 章有提到,和主线程对应是为了方便吧
    forestyuan
        18
    forestyuan  
       2018-01-03 17:42:45 +08:00   ❤️ 1
    问题有误,在 windows 下 UI 有多个线程并不罕见
    nicevar
        19
    nicevar  
       2018-01-03 17:45:47 +08:00   ❤️ 1
    UI 的实际就是屏幕上贴图,就是把一个个元素绘制好然后往屏幕上贴,当然是由一个线程来管理最好了,否则非常难管理,出现一些隐藏非常深的 bug,比如一个父控件里面有多个子控件,一个线程正在遍历属性,另一个线程去移除了一个控件,这不乱套了,资源文件的加载释放处理也容易出错,早期 android 在非 UI 线程更新 UI 时不会报错的,很多初级的开发者经常写出那种在其他线程更新 UI 的逻辑,程序运行看起来很正常,一旦某个特定的情况下程序就挂了

    楼主有次疑问的原因是现在的 UI 开发大多数就是在叠控件,基本上不用自己管理内存了,随便 new 对象随便加载资源,如果自己做个 UI 框架从底层开始绘制就会了解的更清楚了
    fcten
        20
    fcten  
       2018-01-03 17:52:46 +08:00   ❤️ 1
    问题不成立……没有不可行,有的只是设计者对成本与收益的权衡。

    在多窗口的桌面系统中,每一个窗口绑定单独的 UI 线程,在子线程中处理 UI 都是非常常见的。
    ysc3839
        21
    ysc3839  
       2018-01-04 01:54:02 +08:00 via Android   ❤️ 1
    你提问的节点是 iDev,那估计跟苹果的系统有关吧?我之前试过用 Python 写 macOS 下的 GUI 程序,有很多限制。非主线程创建窗口直接失败,fork 的进程也是失败,跨线程操作 UI 也是失败。
    Windows 的话就没那么多事。
    Lision
        22
    Lision  
       2018-01-04 20:32:20 +08:00
    Emmmmm...GSEventReceiveRunLoopMode 在主线程
    Hank1983
        23
    Hank1983  
       2018-01-04 22:29:09 +08:00 via Android
    c#子进程可以操作 UI
    free9fw
        24
    free9fw  
       2018-01-09 17:58:36 +08:00
    因为 runloop 的 kCFRunLoopDefaultMode,app 的默认 mode,主线程才有 runloop,子线程没有 loop。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2983 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 13:59 · PVG 21:59 · LAX 05:59 · JFK 08:59
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.