Python中获取多线程返回值问题

qq_34621405 2017-12-03 09:15:49
现有一个程序,需要打印每个线程的返回值
引用
# -*-coding:utf-8-*-
from time import ctime, sleep
import threading
import numpy as np

loops = ['广州', '北京']
t_list = ['01', '02', '03']
cldas_sum = ['one', 'two', 'three', 'four', 'five', 'six']


class MyThread(object):
def __init__(self, func, args, name=''):
self.name = name
self.func = func
self.args = args

def __call__(self):
self.result = self.func(*self.args)

def get_result(self):
try:
return self.result
except Exception:
return None


def loop(nloop):
global cldas_sum
for j in t_list:
cldas_values = []
for k in range(4):
cldas_value = nloop + str(k)
cldas_values.append(cldas_value)
cldas_values.append(j)
cldas_values.append(nloop)
cldas_sum = np.row_stack((cldas_values, cldas_sum))
print(cldas_sum)
return cldas_sum


def main():
print('start at',ctime())
threads = []
nloops = range(len(loops))
for i in nloops:
t = threading.Thread(target=MyThread(loop, (loops[i],), loop.__name__))
threads.append(t)
for i in nloops: # start threads 此处并不会执行线程,而是将任务分发到每个线程,同步线程。等同步完成后再开始执行start方法
threads[i].start()
for i in nloops: # jion()方法等待线程完成
threads[i].join()
print(threads[i].get_result())
print('DONE AT:', ctime())

if __name__ == '__main__':
main()



前面的洞可以打印出来,在运行到print(threads[i].get_result())时报错,
print(threads[i].get_result())
AttributeError: 'Thread' object has no attribute 'get_result'
get_result方法不是在类中已经写出了吗?请问是哪里出错了
...全文
1910 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq_34621405 2017-12-05
  • 打赏
  • 举报
回复
引用 6 楼 xpresslink 的回复:
你的global cldas_sum = ['one', 'two', 'three', 'four', 'five', 'six']要被多个线程争用读写。 但是python原生的list,dict等数据结构都不是线程安全的,在多线程下不可以直接用。 在读写前要加锁。 要用threading.Lock lock = threading.Lock()即可。在某线程修改list里数据之前,让lock.acquire(),且lock在acquire()之后不能再acquire,否则会报错。 当线程结束后调用lock.release()来释放锁就好了。 如果比较复杂的情况可以threading.Condition 如果嫌麻烦可以直接用Queue模块中的 Queue数据类型,直接当成list用可以。 from Queue import Queue 或者用collections模块中的双向队列数据类型 from collections import deque 因为而Queue和deque,都是线程安全的,因此在满足使用条件下,建议使用队列。
谢谢你这么详细的回复,global cldas_sum 的确是多线程共享的一个数据,你的意思是有两种做法:一种是在线程写入cldas_sum中加锁,写完后再释放。另一种是将cldas_sum设置成queue变量,这样就不用加锁。感觉后面这种方式效率更高。 我针对你和其他网友的建议修改了代码,debug发现脚本直接不执行def loop函数了,返回都是空值,请问是这里 t = MyThread(loop, (loops[i],), loop.__name__)引用错误了吗?
# -*-coding:utf-8-*-
from time import ctime, sleep
import threading
import numpy as np
import collections

loops = ['广州', '北京']
t_list = ['01', '02', '03']
cldas_sum = collections.deque()


class MyThread(threading.Thread):
    def __init__(self, func, args, name=''):
        threading.Thread.__init__(self)
        self.name = name
        self.func = func
        self.args = args

    def __call__(self):
        self.result = self.func(*self.args)

    def get_result(self):
        try:
            return self.result
        except Exception:
            return None


def loop(nloop):
    global cldas_sum
    for j in t_list:
        cldas_values = []
        for k in range(4):
            cldas_value = nloop + str(k)
            cldas_values.append(cldas_value)
        cldas_values.append(j)
        cldas_values.append(nloop)
        cldas_sum.append(cldas_values)
    #print(cldas_sum)
    return cldas_sum


def main():
    print('start at', ctime())
    threads = []
    nloops = range(len(loops))
    for i in nloops:
        t = MyThread(loop, (loops[i],), loop.__name__)
        threads.append(t)
    for i in nloops:   # start threads 此处并不会执行线程,而是将任务分发到每个线程,同步线程。等同步完成后再开始执行start方法
        threads[i].start()
    for i in nloops:   # jion()方法等待线程完成
        threads[i].join()
        print(threads[i].get_result())
    print('DONE AT:', ctime())


if __name__ == '__main__':
    main()
混沌鳄鱼 2017-12-05
  • 打赏
  • 举报
回复
还有一点就是由于Python有GIL造成多线程不能利用多核CPU,密集计算的情况下应该用多进程 CPU几核心开个同样大小的进程池。 from multiprocessing.dummy import Pool pool = Pool(4) result = pool.map(loop, data_list)
混沌鳄鱼 2017-12-05
  • 打赏
  • 举报
回复
你的MyThread类定义得有问题 不要实现__call__方法,不然类的行为就不同了。 要实现run方法才行。 def run(self): self.result = self.func(*self.args) 还有就是你既然已经定义了每个子线程对象的get_result方法了,就不要再定义全局变量收集结果了。
extend 2017-12-05
  • 打赏
  • 举报
回复
引用 7 楼 qq_34621405 的回复:
[quote=引用 5 楼 extend 的回复:] 又看了下,get_result,是你类里的函数,你得先实例化对象才能调用。 你的写法:“t = threading.Thread(target=MyThread(loop, (loops[i],), loop.__name__))”,这个t是"threading.Thread"类。 如果换成:“t=MyThread(loop,(loops[i],),loop.__name__)”这样的写法,t才是你定义的类“MyThread”
# -*-coding:utf-8-*-
from time import ctime, sleep
import threading
import numpy as np

loops = ['广州', '北京']
t_list = ['01', '02', '03']
cldas_sum = ['one', 'two', 'three', 'four', 'five', 'six']


class MyThread(threading.Thread):
    def __init__(self, func, args, name=''):
        threading.Thread.__init__(self)
        self.name = name
        self.func = func
        self.args = args

    def __call__(self):
        self.result = self.func(*self.args)

    def get_result(self):
        try:
            return self.result
        except Exception:
            return None


def loop(nloop):
    global cldas_sum
    for j in t_list:
        cldas_values = []
        for k in range(4):
            cldas_value = nloop + str(k)
            cldas_values.append(cldas_value)
        cldas_values.append(j)
        cldas_values.append(nloop)
        cldas_sum = np.row_stack((cldas_values, cldas_sum))
    #print(cldas_sum)
    return cldas_sum


def main():
    print('start at', ctime())
    threads = []
    nloops = range(len(loops))
    for i in nloops:
        t = MyThread(loop, (loops[i],), loop.__name__)
        threads.append(t)
    for i in nloops:   # start threads 此处并不会执行线程,而是将任务分发到每个线程,同步线程。等同步完成后再开始执行start方法
        threads[i].start()
    for i in nloops:   # jion()方法等待线程完成
        print(threads[i].get_result())
        threads[i].join()
    print('DONE AT:', ctime())


if __name__ == '__main__':
    main()


最终打印出来的是None,而且也试过将print放在join()后面,都是一样的结果 start at Mon Dec 4 18:23:56 2017 None None DONE AT: Mon Dec 4 18:23:56 2017 Process finished with exit code 0 [/quote] 一定是none啊,不知道你是不是一定要用__call__函数,我对__call__的用法不太了解,但是简单解决你问题的方法: 把self.result = self.func(*self.args)放到__init__下
混沌鳄鱼 2017-12-04
  • 打赏
  • 举报
回复
你的global cldas_sum = ['one', 'two', 'three', 'four', 'five', 'six']要被多个线程争用读写。 但是python原生的list,dict等数据结构都不是线程安全的,在多线程下不可以直接用。 在读写前要加锁。 要用threading.Lock lock = threading.Lock()即可。在某线程修改list里数据之前,让lock.acquire(),且lock在acquire()之后不能再acquire,否则会报错。 当线程结束后调用lock.release()来释放锁就好了。 如果比较复杂的情况可以threading.Condition 如果嫌麻烦可以直接用Queue模块中的 Queue数据类型,直接当成list用可以。 from Queue import Queue 或者用collections模块中的双向队列数据类型 from collections import deque 因为而Queue和deque,都是线程安全的,因此在满足使用条件下,建议使用队列。
extend 2017-12-04
  • 打赏
  • 举报
回复
又看了下,get_result,是你类里的函数,你得先实例化对象才能调用。 你的写法:“t = threading.Thread(target=MyThread(loop, (loops[i],), loop.__name__))”,这个t是"threading.Thread"类。 如果换成:“t=MyThread(loop,(loops[i],),loop.__name__)”这样的写法,t才是你定义的类“MyThread”
手无护鸡之力 2017-12-04
  • 打赏
  • 举报
回复
q.get()
手无护鸡之力 2017-12-04
  • 打赏
  • 举报
回复
用Queue试试

from Queue import Queue

q = Queue()
...
q.put(3)
...
print q.get(3)
3
qq_34621405 2017-12-04
  • 打赏
  • 举报
回复
引用 5 楼 extend 的回复:
又看了下,get_result,是你类里的函数,你得先实例化对象才能调用。 你的写法:“t = threading.Thread(target=MyThread(loop, (loops[i],), loop.__name__))”,这个t是"threading.Thread"类。 如果换成:“t=MyThread(loop,(loops[i],),loop.__name__)”这样的写法,t才是你定义的类“MyThread”
# -*-coding:utf-8-*-
from time import ctime, sleep
import threading
import numpy as np

loops = ['广州', '北京']
t_list = ['01', '02', '03']
cldas_sum = ['one', 'two', 'three', 'four', 'five', 'six']


class MyThread(threading.Thread):
    def __init__(self, func, args, name=''):
        threading.Thread.__init__(self)
        self.name = name
        self.func = func
        self.args = args

    def __call__(self):
        self.result = self.func(*self.args)

    def get_result(self):
        try:
            return self.result
        except Exception:
            return None


def loop(nloop):
    global cldas_sum
    for j in t_list:
        cldas_values = []
        for k in range(4):
            cldas_value = nloop + str(k)
            cldas_values.append(cldas_value)
        cldas_values.append(j)
        cldas_values.append(nloop)
        cldas_sum = np.row_stack((cldas_values, cldas_sum))
    #print(cldas_sum)
    return cldas_sum


def main():
    print('start at', ctime())
    threads = []
    nloops = range(len(loops))
    for i in nloops:
        t = MyThread(loop, (loops[i],), loop.__name__)
        threads.append(t)
    for i in nloops:   # start threads 此处并不会执行线程,而是将任务分发到每个线程,同步线程。等同步完成后再开始执行start方法
        threads[i].start()
    for i in nloops:   # jion()方法等待线程完成
        print(threads[i].get_result())
        threads[i].join()
    print('DONE AT:', ctime())


if __name__ == '__main__':
    main()


最终打印出来的是None,而且也试过将print放在join()后面,都是一样的结果 start at Mon Dec 4 18:23:56 2017 None None DONE AT: Mon Dec 4 18:23:56 2017 Process finished with exit code 0
QuantumEnergy 2017-12-03
  • 打赏
  • 举报
回复
一个是threading.Thread 一个是MyThread Thread本来就没有get_resulte method
extend 2017-12-03
  • 打赏
  • 举报
回复
把join写在print后面试试

37,721

社区成员

发帖
与我相关
我的任务
社区描述
JavaScript,VBScript,AngleScript,ActionScript,Shell,Perl,Ruby,Lua,Tcl,Scala,MaxScript 等脚本语言交流。
社区管理员
  • 脚本语言(Perl/Python)社区
  • IT.BOB
加入社区
  • 近7日
  • 近30日
  • 至今

试试用AI创作助手写篇文章吧