2011-11-14 17 views
5

Tôi đã gặp một vấn đề mà tôi không thể giải quyết và nó được kết hợp với đa xử lý và sử dụng nó bên trong trang trí.Sử dụng đa xử lý bên trong trang trí tạo lỗi: không thể chọn chức năng ... nó không được tìm thấy là

Khi tôi gọi phương thức run_in_parallels sử dụng đa tôi đang nhận được lỗi:

Can't pickle <function run_testcase at 0x00000000027789C8>: it's not found as __main__.run_testcase

Cuộc gọi diễn ra bên trong trang trí, sau đó theo các vấn đề nêu trên. Tại thời điểm gọi cùng một phương thức run_in_parallels mà không có trang trí tất cả đều hoạt động bình thường.

Lý do của sự cố này là gì?


file: w_PythonHelper.py

desc: Function 'run_in_parallel' được sử dụng để chạy nhiều quy trình cùng một lúc. Phương pháp đầu tiên, mà sẽ kết thúc hoạt động dừng những người khác.

from multiprocessing import Process,Event 

class ExtProcess(Process): 
    def __init__(self, event,*args,**kwargs): 
     self.event=event 
     Process.__init__(self,*args,**kwargs) 

    def run(self): 
     Process.run(self) 
     self.event.set() 

class PythonHelper(object): 
    @staticmethod 
    def run_in_parallel(*functions): 
     event=Event() 
     processes=dict() 
     for function in functions: 
      fname=function[0] 
      try:fargs=function[1] 
      except:fargs=list() 
      try:fproc=function[2] 
      except:fproc=1 
      for i in range(fproc): 
       process=ExtProcess(event,target=fname,args=fargs) 
       process.start() 
       processes[process.pid]=process 
     event.wait() 
     for process in processes.values(): 
      process.terminate() 
     for process in processes.values(): 
      process.join() 

file: w_Recorder.py

desc: chức năng 'bắt' được sử dụng để lấy một ảnh chụp màn hình

from PIL import ImageGrab 
import time 

class Recorder(object): 
    def capture(self): 
     ImageGrab.grab().save("{f}.{e}".format(f=time.time(),e="png")) 

file: w_Decorators.py

desc: Chạy song song một chức năng nhất định cùng với một phương pháp 'bắt' của lớp 'ghi'

from w_Recorder import Recorder 
from w_PythonHelper import PythonHelper 

def check(function): 
    def wrapper(*args): 
     try: 
      recorder=Recorder() 
      PythonHelper.run_in_parallel([function,args],[recorder.capture]) 
      print("success") 
     except Exception as e: 
      print("failure: {}".format(e)) 
     return function 
    return wrapper 

file: w_Logger.py

desc: chương trình chính (tạo ra lỗi)

from w_Decorators import check 
import time 

class Logger(object): 

    @check 
    def run_testcase(self): 
     # example function (runtime: 20s) 
     for i in range(20): 
      print("number: {}".format(i)) 
      time.sleep(1) 

    def run_logger(self): 
     self.run_testcase() 


if __name__=="__main__": 
    logger=Logger() 
    logger.run_logger() 

tệp: w_Logger.py

desc: chương trình chính (chỉ hoạt động corectly)

from w_PythonHelper import PythonHelper 
from w_Recorder import Recorder 
import time 

class Logger(object): 

    def run_testcase(self): 
     # example function (runtime: 20s) 
     for i in range(20): 
      print("number: {}".format(i)) 
      time.sleep(1) 

    def run_logger(self): 
     recorder=Recorder() 
     PythonHelper.run_in_parallel([self.run_testcase],[recorder.capture]) 

if __name__=="__main__": 
    logger=Logger() 
    logger.run_logger() 

sự khác biệt mà các phương pháp này cùng thể hiện trong hai trường hợp làm việc khác nhau là gì?


EDIT: Có ai có ý tưởng giải quyết vấn đề này (lỗi Python này) không? Nếu không, có thể ai đó biết cách chụp ảnh màn hình tốt khi ứng dụng đang chạy?

Thật sự tôi thấy câu hỏi tương tự: multiprocessing.Process subclass works on Linux but not Windows

Câu trả lời là: To fix this, you can remove the process member., nhưng làm thế nào tôi có thể làm điều này cho ví dụ của tôi.

Trong khi gỡ lỗi xảy ra khi gọi process.start() trong run_in_parallel(*functions)


EDIT2: như ivan_pozdeev đã viết: tôi có thể sử dụng wrapper như một chức năng, nhưng không thể sử dụng nó như là trang trí. Tôi có nhiều chức năng được trang trí bởi trang trí này và cách đơn giản nhất là sử dụng đa xử lý bên trong trang trí. Nhưng đáng tiếc là tôi không thể giải quyết vấn đề này. Có thể ai đó đã giải quyết được một vấn đề tương tự. Tôi sẽ biết ơn vì bất kỳ gợi ý nào.

'run_in_parallel' hoạt động như tôi muốn. Hai hoặc nhiều hàm chạy song song và hàm đầu tiên, được hoàn thành buộc kết thúc hàm thứ hai. Khi tôi gọi wrapper (chức năng, * args) thì chức năng hoạt động ok, khi tôi đặt cơ chế này bên trong trang trí tôi nhận được 'không thể chọn chức năng ... nó không được tìm thấy như' lỗi. Thông tin chi tiết có thể được tìm thấy trên

Traceback của tôi:

Traceback (most recent call last): 
    File "C:\Interpreters\Python32\lib\pickle.py", line 679, in save_global 
    klass = getattr(mod, name) 
AttributeError: 'module' object has no attribute 'run_testcase' 

During handling of the above exception, another exception occurred: 

Traceback (most recent call last): 
    File "C:\EskyTests\w_Logger.py", line 19, in <module> 
    logger.run_logger() 
    File "C:\EskyTests\w_Logger.py", line 14, in run_logger 
    self.run_testcase() 
    File "C:\EskyTests\w_Decorators.py", line 14, in wrapper 
    PythonHelper.run_in_parallel([function,args],[recorder.capture]) 
    File "C:\EskyTests\w_PythonHelper.py", line 25, in run_in_parallel 
    process.start() 
    File "C:\Interpreters\Python32\lib\multiprocessing\process.py", line 130, in start 
    self._popen = Popen(self) 
    File "C:\Interpreters\Python32\lib\multiprocessing\forking.py", line 267, in __init__ 
    dump(process_obj, to_child, HIGHEST_PROTOCOL) 
    File "C:\Interpreters\Python32\lib\multiprocessing\forking.py", line 190, in dump 
    ForkingPickler(file, protocol).dump(obj) 
    File "C:\Interpreters\Python32\lib\pickle.py", line 237, in dump 
    self.save(obj) 
    File "C:\Interpreters\Python32\lib\pickle.py", line 344, in save 
    self.save_reduce(obj=obj, *rv) 
    File "C:\Interpreters\Python32\lib\pickle.py", line 432, in save_reduce 
    save(state) 
    File "C:\Interpreters\Python32\lib\pickle.py", line 299, in save 
    f(self, obj) # Call unbound method with explicit self 
    File "C:\Interpreters\Python32\lib\pickle.py", line 623, in save_dict 
    self._batch_setitems(obj.items()) 
    File "C:\Interpreters\Python32\lib\pickle.py", line 656, in _batch_setitems 
    save(v) 
    File "C:\Interpreters\Python32\lib\pickle.py", line 299, in save 
    f(self, obj) # Call unbound method with explicit self 
    File "C:\Interpreters\Python32\lib\pickle.py", line 683, in save_global 
    (obj, module, name)) 
_pickle.PicklingError: Can't pickle <function run_testcase at 0x00000000027725C8>: it's not found as __main__.run_testcase 

Trả lời

1

Tricky, nhưng tôi nghĩ những gì đang xảy ra là check cửa hàng một tham chiếu đến phương pháp cởi ra khi các lớp được định nghĩa. Ví dụ làm việc sử dụng tham chiếu đến phương thức bị ràng buộc self.run_testcase khi bạn gọi run_logger.

Tôi nghĩ rằng điều tốt nhất là thử làm cho run_testcase một hàm mức cao nhất, chứ không phải là một phương thức của một lớp.

Ngoài ra, chức năng capture của bạn có thể sẽ không làm những gì bạn mong đợi - thời gian hiện tại sẽ được lưu trữ khi chức năng được xác định và mọi ảnh chụp màn hình sẽ được lưu lại trước đó. Bạn có thể muốn gọi time.time() bên trong hàm.

+0

Khi tôi đang làm 'run_testcase' một hàm mức cao nhất như bạn đã đề cập sau đó tôi nhận được một lỗi khác:' Không thể chọn : nó không phải là đối tượng giống như __main __. Run_testcase_proc'. Thật không may, nó phải là một phương pháp của một lớp học. Tôi phải sửa đổi trang trí hiện tại, để áp dụng chức năng mới sẽ được thực hiện song song với 'run_testcase'. Hàm 'time.time()' là một vấn đề nhỏ và chỉ được sử dụng để giữ một số thứ tự, nó có thể dễ dàng là một số, ví dụ 1,2,3 ... Vấn đề chính là sửa đổi trang trí. –

+1

@ falek.marcin: Từ các tài liệu đa xử lý: "không thể sử dụng trực tiếp các phương thức ràng buộc hoặc không ràng buộc làm đối số đích trên Windows" (http://docs.python.org/dev/library/multiprocessing#windows) –

+0

Có thể có giải pháp thay thế hoặc giải pháp thay thế để sửa đổi trang trí. Có ai có một ý tưởng làm thế nào để giải quyết nó một cách khác nhau? –

4

Chức năng bạn đang chuyển đến Process.__init__() không thể chọn trong Windows. Đọc 16.6 multiprocessing - Programming guidelines - Windows.

Liên quan đến lỗi của bạn với chức năng cấp cao nhất - Tôi nghi ngờ cách bạn định nghĩa nó, nó được tạo khác nhau mỗi lần và do đó thực sự là "không cùng một đối tượng" ở trẻ. Tôi khuyên bạn nên chuyển một hàm mức cao nhất đơn giản có thể gọi run_testcase bằng cách sử dụng sự phản chiếu nếu bạn thực sự cần mức độ tinh tế này. Cập nhật: cách này không hiệu

Cập nhật:

tôi đã thực hiện công việc này bằng cách undecorating run_testcase, run_in_parallelcapture.@check trang trí được thay thế bằng def wrapper(function,*args) với chức năng tương tự:

import traceback 
def wrapper(function,*args): 
    try: 
     recorder=Recorder() 
     PythonHelper().run_in_parallel([function,args],[recorder.capture]) 
     print("success") 
    except Exception,e: 
     print("failure: "+traceback.format_exc(10)) 

chính:

from w_Decorators import wrapper 

if __name__=="__main__": 
    logger=Logger() 
    wrapper(logger.run_testcase) 

Cũng giống như tôi nghĩ - vật trang trí không picklable.

+0

Bạn có thể cho biết bạn sẽ làm như thế nào dựa trên ví dụ của tôi? –

+0

Xem các chỉnh sửa của tôi ở trên. Bằng cách này, logic trong run_in_parallel() có thể không chính xác. –

+0

_ @ kiểm tra trang trí đã được thay thế bằng def wrapper (chức năng, * args) với cùng chức năng_ không, đây không phải là chức năng tương tự. Lưu ý rằng tôi đã viết rằng ** Tôi phải sử dụng ** một cú pháp trang trí. Tôi chỉ có rất nhiều phương pháp được trang trí theo cách như vậy. –

Các vấn đề liên quan