制造“插座.接受“在一个线程中,在另一个线程中的某些代码之前执行?”?(Python3)

2024-09-29 17:10:00 发布

您现在位置:Python中文网/ 问答频道 /正文

我希望python执行(类似于subprocess.Popen()?)在socket.accept()处有另一个线程要阻止之后的外部套接字连接器。在

import socket
import threading
import subprocess

host = '0.0.0.0'
port = 3333


def getsock():
    server_sock = []

    def getsock_server():
        sock = socket.socket()
        sock.bind((host, port))
        sock.listen(1)
        accept_return = sock.accept()  # *** CRITICAL ACCEPT ***
        server_sock.append(accept_return[0])
        address = accept_return[1]
        return address

    thr = threading.Thread(target=getsock_server)
    thr.start()
    """Something that *must* be done after the CRITICAL ACCEPT 
       line is executing and the thread "thr" is blocked. Otherwise
       the program malfunctions and blows into some undebuggable
       complexity. ;(
       Although it is a connect operation, it may not be as innocent
       as belowing lines:        
           client_sock = socket.socket()
           client_sock.connect((host, port))
    """
    p = subprocess.Popen(
        ["./connector"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)

    thr.join()
    return server_sock[0]


conn, addr = getsock()

基本上,我需要按以下顺序进行工作:

^{pr2}$

如果3)在2)之前,就会产生不良后果。在

没有线程的解决方案是不可能的(我首先肯定地认为,因为线程是麻烦的….)因为当我socket.accept()我不能在不中断接受的情况下subprocess.Popen()。在

另外,我不想使用time.sleep(SOME_LARGE_VALUE),因为它也是不可控制的(容易出错,我使用的词是否正确?)而且,速度慢。在

我了解到:Python3(CPython)有全局解释器锁(GIL)机制。一次只有一个线程有机会执行。如果一个线程阻塞(在本例中是socket.accept()),CPython将转向另一个线程。(但是,这无助于解决问题….)

有人知道一种Python式的方式来执行命令吗?在


Tags: theimporthostreturnserverisportsocket
2条回答

listen通知网络堆栈开始在后台对传入的连接请求进行排队。对accept的每个调用都接受队列中的下一个请求。看起来你的子进程想连接回这个程序。听完后再打电话。在

import socket
import threading
import subprocess

host = '0.0.0.0'
port = 3333


def getsock():
    server_sock = []
    sock = socket.socket()
    sock.bind((host, port))
    sock.listen(1)
    p = subprocess.Popen(
        ["./connector"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    return sock.accept()  # *** CRITICAL ACCEPT ***

conn, addr = getsock()

你已经得到了你的具体案例的有效答案。但是,如果您更喜欢一个更通用的解决方案来解决更一般的问题,那么几乎没有不同的方法可以实现这一点。在

让我们定义一个问题:我想调度一个任务,准备一些资源给工作线程,然后在主线程中等待资源准备就绪。资源的准备只进行一次。当然,仍然有一个有效的问题:为什么我们不能在一个线程中按顺序运行所有的东西?但是让我们把这看作是一个介绍多线程世界的练习。在

下面是一些基本的python代码:

import threading
import time
import random

data_ready=False

def do_sth():
    global data_ready

    def prepare_sth():
        global data_ready
        print("preparing, simulated by random wait")
        time.sleep(random.randrange(5,10))
        data_ready=True
        print("resource is ready")

    print("do_sth");
    thr = threading.Thread(target=prepare_sth)
    thr.start()

    # WAIT HERE

    if data_ready:
        print("OK")
    else:
        print("ERROR")

do_sth()

当然,它并不像预期的那样工作,并且在输出的某个地方会有一条ERROR消息。但我们可以把问题改成:什么取代了WAIT HERE

解决此类问题最明显也是最糟糕的方法是主动等待:

^{pr2}$

尝试运行这段代码并观察(在Linux上使用top)CPU使用情况。你会注意到它在等待中长大。所以,请不要在现实生活中做这样的事情。在

规定资源准备只进行一次。所以,工作线程可以准备数据,然后我们可以等待这个线程在主线程中完成。在这种情况下,这是我的首选解决方案。在

thr.join()

最后,使用一个完整的锁和条件变量方案。它需要更多的更改,因此完整的代码粘贴在这里:

import threading
import time
import random

data_ready=False

def do_sth():
    global data_ready
    lock=threading.Lock()
    cond=threading.Condition(lock)

    def prepare_sth():
        global data_ready
        with cond:
            print("preparing, simulated by random wait")
            time.sleep(random.randrange(5,10))
            data_ready=True
            print("resource is ready")
            cond.notify()

    print("do_sth");
    with cond:
        thr = threading.Thread(target=prepare_sth)
        thr.start()
        while not data_ready:
            print("waiting")
            cond.wait()

        if data_ready:
            print("OK")
        else:
            print("ERROR")

do_sth()

如果您需要在一个线程中以循环方式准备资源(例如,一些数据),并在另一个线程中使用它,这将是一种合适的方法。请查找生产者-消费者模型。在

最后但并非最不重要。我为global变量使用了global说明符,因为我很懒,而且这个例子是关于不同的东西的。但是,把它看作是一个糟糕的设计。变量只能在do_sthprepare_sth线程之间共享。您可以使用argskwargs方法的参数。在

相关问题 更多 >

    热门问题