【问题标题】:In python is the .start() command blocking for the time it takes the thread start to complete?在 python 中,.start() 命令在线程启动完成的时间内阻塞?
【发布时间】:2022-01-14 16:18:18
【问题描述】:

假设: 线程....start() 阻塞,直到启动完成。
题: 假设是对还是错?

Start http web server then open browser 有以下代码。

import sys
import time
import threading
import webbrowser
from http.server import HTTPServer, SimpleHTTPRequestHandler

ip = "127.0.0.1"
port = 3600
url = f"http://{ip}:{port}"


def start_server():
    server_address = (ip, port)
    httpd = HTTPServer(server_address, SimpleHTTPRequestHandler)
    httpd.serve_forever()


threading.Thread(target=start_server).start()
webbrowser.open_new(url)

while True: # make a blocker to prevent the application finish of execute:
    try:
        time.sleep(1)
    except KeyboardInterrupt:
        sys.exit(0)

这很好用。但是,以下方法也有效。

import sys
import time
import threading
import webbrowser
from http.server import HTTPServer, SimpleHTTPRequestHandler

ip = "127.0.0.1"
port = 3600
url = f"http://{ip}:{port}"


def start_server():
    server_address = (ip, port)
    httpd = HTTPServer(server_address, SimpleHTTPRequestHandler)
    httpd.serve_forever()


threading.Thread(target=start_server).start()
webbrowser.open_new(url)

假设: thread....start() 实际上会阻塞,直到 start 完成。因此,webbrowser.open_new(url) 在启动完成之前不会执行。从而使以下内容变得不必要。

while True: # make a blocker to prevent the application finish of execute:
    try:
        time.sleep(1)
    except KeyboardInterrupt:
        sys.exit(0)

经过大量搜索,我无法证明或反驳假设。

【问题讨论】:

  • 请记住,因为如果使用 Python GIL(全局解释器锁),一次只有一个线程可以执行 Python 代码。当您的线程启动时,它会占用 CPU,直到线程阻塞 I/O 或输入一些非 Python 代码,然后主线程才能继续。无法保证这一点,但它就是这样工作的。
  • 是的,就像 Tim 说的,Python 是单线程的;如果您想要真正的并行性,则必须使用多处理。
  • @TimRoberts 尽管由于 GIL,一次只执行一个线程,Python 运行时可以(并且将)更改正在运行的线程,独立于 I/O 阻塞或运行非 Python 代码:线程-change 可以发生在 Python VM 上的任何字节码指令边界。正如您所描述的那样,为您提供确定性和用户可控的上下文切换的是基于异步的代码。
  • 伙计们:像这样的 HTTP 服务器在 Python 中使用多线程非常好:等待 http 连接到达是 I/O 阻塞,而其他线程只是以透明的方式运行。跨度>

标签: python multithreading


【解决方案1】:

按照您建议的方式调用Thread.start() 时没有阻塞。 从某种意义上说,调用是阻塞的,即放置了一个初始化新线程内部状态的调用,并且进行了一个系统调用来启动实际的 OS 线程——但这应该花费不到 1 毫秒。作为线程目标的函数仅在新线程上调用,主线程将继续运行,无论该函数内部发生什么。

如果您不希望程序结束,则无需像您设置的那样采用复杂的暂停循环 - 只需调用 threading.join() 即可。 将阻塞,直到所有其他线程结束运行,只有他们调用join()的线程才会继续。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多