1

我正在尝试开发一个使用 pika 和线程模块的 Python 3.6 脚本。

我有一个问题,我认为这是由于我的 A)对 Python 和一般编码非常陌生,以及 B)我不明白如何在函数在单独的线程中运行并且已经在括号中传递参数时如何在函数之间传递变量在接收函数名称的末尾。

我之所以这样认为,是因为当我不使用线程时,我可以简单地通过调用接收函数名称并提供要传递的变量来在函数之间传递一个变量,在括号中,一个基本示例如下所示:

def send_variable():
    body = "this is a text string"
    receive_variable(body)

def receive_variable(body):
    print(body)

这在运行时打印:

this is a text string

我需要使用线程的代码的工作版本如下所示 - 它使用直接函数(无线程),我使用 pika 通过 pika 回调函数从(RabbitMQ)队列接收消息,然后我通过在“回调”函数中收到的消息正文到“处理函数”:

import pika
...mq connection variables set here...


# defines username and password credentials as variables set at the top of this script
    credentials = pika.PlainCredentials(mq_user_name, mq_pass_word)

# defines mq server host, port and user credentials and creates a connection
    connection = pika.BlockingConnection(pika.ConnectionParameters(host=mq_host, port=mq_port, credentials=credentials))

# creates a channel connection instance using the above settings
    channel = connection.channel()

# defines the queue name to be used with the above channel connection instance
    channel.queue_declare(queue=mq_queue)


def callback(ch, method, properties, body):

# passes (body) to processing function
    body_processing(body)

# sets channel consume type, also sets queue name/message acknowledge settings based on variables set at top of script
    channel.basic_consume(callback, queue=mq_queue, no_ack=mq_no_ack)
# tells the callback function to start consuming
    channel.start_consuming()
# calls the callback function to start receiving messages from mq server
    callback()
# above deals with pika connection and the main callback function


def body_processing(body):
    ...code to send a pika message every time a 'body' message is received...

这很好用,但是我想将其翻译为在使用线程的脚本中运行。当我这样做时,我必须将参数“channel”提供给在其自己的线程中运行的函数名称 - 然后尝试包含“body”参数,以便“processing_function”看起来如下所示:

def processing_function(channel, body):

我收到一条错误消息:

[function_name] is missing 1 positional argument: 'body'

我知道在使用线程时需要更多代码,并且我在下面包含了用于线程的实际代码,以便您可以看到我在做什么:

...imports and mq variables and pika connection details are set here...

def get_heartbeats(channel):
channel.queue_declare(queue=queue1)
#print (' [*] Waiting for messages. To exit press CTRL+C')

    def callback(ch, method, properties, body):

        process_body(body)

        #print (" Received %s" % (body))

    channel.basic_consume(callback, queue=queue1, no_ack=no_ack)
    channel.start_consuming()


def process_body(channel, body):
    channel.queue_declare(queue=queue2)
    #print (' [*] Waiting for Tick messages. To exit press CTRL+C')

# sets the mq host which pika client will use to send a message to
    connection = pika.BlockingConnection(pika.ConnectionParameters(host=mq_host))
# create a channel connection instance
    channel = connection.channel()
# declare a queue to be used by the channel connection instance
    channel.queue_declare(queue=order_send_queue)
# send a message via the above channel connection settings
    channel.basic_publish(exchange='', routing_key=send_queue, body='Test Message')
# send a message via the above channel settings
# close the channel connection instance
    connection.close()


def manager():

# Channel 1 Connection Details - =======================================================================================

    credentials = pika.PlainCredentials(mq_user_name, mq_password)
    connection1 = pika.BlockingConnection(pika.ConnectionParameters(host=mq_host, credentials=credentials))
    channel1 = connection1.channel()

# Channel 1 thread =====================================================================================================
    t1 = threading.Thread(target=get_heartbeats, args=(channel1,))
    t1.daemon = True
    threads.append(t1)
    # as this is thread 1 call to start threading is made at start threading section

# Channel 2 Connection Details - =======================================================================================

    credentials = pika.PlainCredentials(mq_user_name, mq_password)
    connection2 = pika.BlockingConnection(pika.ConnectionParameters(host=mq_host, credentials=credentials))
    channel2 = connection2.channel()

# Channel 2 thread ====================================================================================================
    t2 = threading.Thread(target=process_body, args=(channel2, body))
    t2.daemon = True
    threads.append(t2)
    t2.start()  # as this is thread 2 - we need to start the thread here

# Start threading
t1.start()  # start the first thread - other threads will self start as they call t1.start() in their code block
for t in threads: # for all the threads defined
    t.join()  # join defined threads

manager()  # run the manager module which starts threads that call each module

这在运行时会产生错误

process_body() missing 1 required positional argument: (body)

我不明白为什么会这样或如何解决它。

感谢您抽出宝贵时间阅读此问题,非常感谢您提供的任何帮助或建议。

请记住,我是 python 和编码的新手,所以可能需要拼写出来,而不是能够理解更多神秘的回复。

谢谢!

4

1 回答 1

1

在进一步研究这一点并使用代码时,似乎如果我编辑这些行:

def process_body(channel, body):

读书

def process_body(body):

t2 = threading.Thread(target=process_body, args=(channel2, body))

使其内容为:

t2 = threading.Thread(target=process_body)

那么代码似乎可以根据需要工作 - 我还在 htop 中看到多个脚本进程,所以看起来线程正在工作 - 我已经离开脚本处理 24 小时 + 并且没有收到任何错误......

于 2017-08-01T10:18:37.980 回答