【问题标题】:python thread.start() doesn't run to completion before switching context?python thread.start() 在切换上下文之前没有运行完成?
【发布时间】:2019-07-27 15:34:46
【问题描述】:

有人能解释一下 Python 线程是如何工作的吗? thread.start() 在切换回另一个上下文(如下面的 main)之前是否没有运行目标函数完成?

import time
import threading

def threadfunc():
    # time.sleep(1)
    print('thread print 1', flush=True)
    print('thread print 2', flush=True)
    #time.sleep(1)

print('before thread', flush=True)

thread1 = threading.Thread(target=threadfunc)
thread1.start()

print('after thread', flush=True)

输出:

before thread
thread print 1
after thread
thread print 2 #shouldn't this be after "print 1"?

【问题讨论】:

  • 如果thread.start() 会等待线程完成,那么使用线程的意义何在?
  • 在国内。不应在“print1”之后打印。您正在一个独立的线程中运行该函数。所以代码将继续执行。这就是我们使用线程的原因,所以代码执行不会等到函数完成,否则在第一种情况下线程的意义何在
  • 你们俩都没有解释 Python 代码是如何确定执行的。线程仍然被 GIL 阻塞,所以通常你会期望 python 代码在切换出上下文之前完成。线程必须切换到非运行状态,例如使用睡眠功能或执行一些 IO。是因为 print() 被认为是一个输出函数,然后使线程切换上下文?
  • Re,“……是因为 print() 是……输出函数吗?”可能是。我不知道 C Python 的内部原理,但我会假设对操作系统的任何调用都可能是一个让步点,并且我会假设任何可能阻塞 I/O 的系统调用肯定必须 i> 成为屈服点。如果这不是真的,并且如果您不能使用线程进行多处理(由于 GIL,您不能这样做),那么实际上就没有使用线程的理由了。
  • C Python 线程不必在运行的整个过程中保持 GIL 持续锁定。它只需要在访问可能与其他线程共享的数据结构(例如,任何 Python 对象)时锁定它。原则上,它可以在每两个原始语句之间解锁、屈服,然后再次锁定。我不知道这是否是它实际上所做的,但我确信(由于我上面给出的原因)它必须在每次可能阻塞的系统调用之前解锁 GIL。

标签: python python-3.x multithreading python-multithreading


【解决方案1】:

正如 cmets 所解释的,这不是线程或 GIL 在 Python 中的工作方式

许多 CPython 底层的 C 代码将释放 GIL,IO 操作(如 Solomon 所述)会这样做,而一些库(例如 NumPy)显式释放它只是为了帮助多线程代码运行得更快

解释器还将尝试在每个few milliseconds 切换线程

查看https://stackoverflow.com/a/49573860/1358308了解更多详情

【讨论】:

    猜你喜欢
    • 2018-07-30
    • 2012-08-01
    • 1970-01-01
    • 2018-10-29
    • 2021-10-02
    • 1970-01-01
    • 2011-06-02
    相关资源
    最近更新 更多