Python Как реализовать многопоточность моего класса электронной почты - PullRequest
0 голосов
/ 13 июля 2020

У меня довольно большой класс электронной почты, который создает и отправляет различные электронные письма с mime, вложениями и т. Д. c. Все работает нормально, но вызывается из моего основного l oop, а метод sendmail, использующий smtplib, иногда может блокироваться на несколько секунд из-за проблем на другом конце. Я хочу запустить код в новом потоке, чтобы мой основной l oop мог продолжать работать.

Я безуспешно пробовал два подхода:

  • Вызов моего класса с использованием потока

  • Наследовать мой класс V1 от потока

Не останавливайте блокировку. Ниже представлен рабочий скелет моего класса (V1) и то, что я пробовал. Успех был бы увидеть, что «Готово» появляется сразу после «Запуск», вместо того, чтобы ждать 3 секунды для sendmail на fini sh. Надеюсь, что есть простой способ сделать это ...

from time import sleep
from threading import Thread

class EMailv1():
    def __init__(self):
        self._from_address = 'a@b.com'
        self._to_addresslist = []

    def buildmessage(self, **kwargs):
        message ={}
        return message

    @staticmethod
    def sendmail(message):
        sleep(5)
        return

class EMailv2(Thread):
    def __init__(self):
        Thread.__init__(self)
        self._from_address = 'a@b.com'
        self._to_addresslist = []

    def run(self):
        pass

    def buildmessage(self, **kwargs):
        message ={}
        return message

    @staticmethod
    def sendmail( message):
        sleep(3)
        return


if __name__ == "__main__":
    print('Starting V1 class send in current manner, which blocks if smtplib cannot deliver mail')
    email =EMailv1()
    msg = email.buildmessage(a='a',b='b')
    email.sendmail(msg)
    print('v1 Done after sendmail sleep finishes')

    print('Starting  threaded call to send V1 class')
    email = EMailv1()
    msg = email.buildmessage(a='a',b='b')
    t = Thread(target=email.sendmail(msg))
    t.start()
    print('Threaded call of V1 Done after sendmail sleep finishes')

    print('Starting V2 class inheriting Thread')
    email = EMailv2()
    msg = email.buildmessage(a='a',b='b')
    email.start()
    email.sendmail(msg)
    print('V2 Done after sendmail sleep finishes')

1 Ответ

1 голос
/ 13 июля 2020

Во второй версии вместо

t = Thread(target=email.sendmail(msg))

вы должны сделать

t = Thread(target=email.sendmail, args=[msg])

Как вы написали, он оценивает email.sendmail(msg) перед построение потока, поэтому вы видите, что вы ждете 5 секунд, прежде чем продолжить.

Вместо этого вы должны передать потоку целевую функцию и ее аргументы отдельно, без их оценки.

Вот фиксированный и минимизированная версия:

from time import sleep
from threading import Thread

class EMailv1():
    def __init__(self):
        self._from_address = 'a@b.com'
        self._to_addresslist = []

    def buildmessage(self, **kwargs):
        message ={}
        return message

    @staticmethod
    def sendmail(message):
        sleep(5)
        print("Launched thread: I'm done sleeping!")
        return

if __name__ == "__main__":
    print('Main thread: Starting  threaded call to send V1 class')
    email = EMailv1()
    msg = email.buildmessage(a='a', b='b')
    t = Thread(target=email.sendmail, args=[msg])
    t.start()
    print("Main thread: I have created the thread, and am done.")

Вывод:

Main thread: Starting  threaded call to send V1 class
Main thread: I have created the thread, and am done.
Launched thread: I'm done sleeping!

С учетом сказанного, я также предлагаю вам взглянуть на некоторые абстракции, предоставленные в Python для выполнения многопоточной работы . Например, обратите внимание на такие функции, как ThreadPoolExecutor - обычно они предпочтительнее работать напрямую с Thread s.

...