2015-10-15 7 views
1

Я пытаюсь запустить процесс в отдельном потоке, но он замораживает мой Gui, и я не могу понять, почему.Qthread блокировка Gui PySide

Я инициализация нити в функции инициализации моего класса:

self.cipher = Cipher() 
self.cipher_thread = QThread() 
self.cipher.moveToThread(self.cipher_thread) 

self.cipher_thread.started.connect(lambda: self.cipher.encrypt(self.plaintext_file_path, 
                     self.ciphertext_file_path, 
                     self.init_vector, 
                     self.key)) 

self.cipher_thread.start() 

Метод шифрования криптографического класса:

def encrypt(self): 
    # check that both the key and the initialisation vector are 16 bytes long 
    if len(self.k) == self.key_byte_length and len(self.init_vector) == self.byte_length: 
     if not self.used: 
      self.used = True 

      # get the padding bytes and store in a list 
      self.padding_bytes = self.__getPaddingBytes() 

      # generate sub keys 
      # initial subkey is first four words from key 
      init_subkey_words = [] 
      for i in range(0, self.key_byte_length-3,4): 
       init_subkey_words.append(self.k[i:i+4]) 

      self.__genSubKeys(init_subkey_words) 

      # read file and append the padding to it 
      with open(self.plaintext_file_path, 'rb') as f: 
       self.plaintext_data = bytearray(f.read()) 
      self.plaintext_data += self.padding_bytes 

      # set total size 
      self.total_size_bytes = len(self.plaintext_data) 

      # insert the initialisation vector as the first 16 bytes in the ciphertext data 
      self.ciphertext_data = self.init_vector 

      ''' 
      begin encryption 
      -------------------------------------------------------------------------------------------------------- 
      ''' 
      self.start_time = datetime.datetime.now() 
      # loop through the file 16 bytes at a time 
      for i in range(0, int(len(self.plaintext_data)), self.byte_length): # i increases by 16 each loop 
       # if self.block_time is not None: 
        # print('block time is', datetime.datetime.now()-self.block_time) 
       self.block_time = datetime.datetime.now() 

       # set the 16 byte state - bytearray Object 
       state = copy.deepcopy(self.plaintext_data[i:i+self.byte_length]) 

       # xor the state with the initialisation vector and first subkey 
       for j in range(self.byte_length): 
        state[j] ^= self.init_vector[j] 
        state[j] ^= self.sub_keys[0][j] 

       # round start 
       # -------------------------------------------------------------------------------------------------- 
       for j in range(self.num_rounds): 
        self.current_round += 1  # increment current round counter 

        ''' 
        arrange the data into a 4x4 matrix 
        [[1, 5, 9, 13], 
        [2, 6, 10, 14], 
        [3, 7, 11, 15], 
        [4, 8, 12, 16]] 
        ''' 
        state_matrix = np.array(state) 
        state_matrix.resize(4, 4) 
        state_matrix.swapaxes(0, 1) 

        # byte substitution 
        # ---------------------------------------------------------------------------------------------- 
        for row in state_matrix: 
         for byte in row: 
          byte = self.__sBoxSubstitution(byte) 

        # shift row - row k shifts left k places 
        # ---------------------------------------------------------------------------------------------- 
        state_matrix = state_matrix.tolist() 
        for row in range(1, 4): 
         for l in range(0, row): 
          state_matrix[row].append(state_matrix[row].pop(0)) 
        state_matrix = np.array(state_matrix) 


        # mix column - not included in last round 
        # ---------------------------------------------------------------------------------------------- 
        if self.current_round is not self.num_rounds: 
         # swap axes of state matrix 
         state_matrix.swapaxes(0, 1) 

         # create temporary holder for the computed values 
         mixed_col_bytes = [[], [], [], []] 

         for k in range(4): 
          for l in range(4): 
           mixed_col_bytes[k].append(
            self.__GFMult(self.MIX_COL_MATRIX[l][0], state_matrix[k][0])^
            self.__GFMult(self.MIX_COL_MATRIX[l][1], state_matrix[k][1])^
            self.__GFMult(self.MIX_COL_MATRIX[l][2], state_matrix[k][2])^
            self.__GFMult(self.MIX_COL_MATRIX[l][3], state_matrix[k][3])) 

         # restore state matrix from temporary holder and swap axes back 
         state_matrix = np.array(copy.deepcopy(mixed_col_bytes)) 
         state_matrix.swapaxes(0, 1) 

        # restore single bytearray state 
        state_matrix = state_matrix.flatten() 
        state_matrix = state_matrix.tolist() 
        state = bytearray(state_matrix) 

        # key addition 
        # ---------------------------------------------------------------------------------------------- 
        for k in range(self.byte_length): 
         state[k] ^= self.sub_keys[self.current_round][k] 

       self.ciphertext_data += state     # append state to ciphertext data 
       self.init_vector = self.ciphertext_data[-16:] # update the initialisation vector 
       self.current_round = 0       # reset current round number 
       self.completed_size_bytes += self.byte_length 
       self.percent_done = (self.completed_size_bytes/self.total_size_bytes)*100 

       self.updateProgressSig.emit(int(self.percent_done)) 
      # finish encryption 
      self.__saveEncryptedData() 
      print('total encryption time:', datetime.datetime.now() - self.start_time) 
      # finish 
      self.finish(self.ciphertext_file_path) 

    # either the key of the initialisation vector are not the correct length 
    else: 
     print(' either the key length or initialisation vector is the wrong length') 
     print('---') 
     print('key length:', len(self.k)) 
     print('iv length:', len(self.init_vector)) 
+0

Это, вероятно, не имеет никакого значения, но попытайтесь устранить «лямбда» - например. передайте аргументы конструктору 'Cipher' и подключите сигнал непосредственно к' self.cipher.encrypt' (который должен быть украшен '@ QtCore.Slot'). Если это не имеет никакого эффекта, возможно, просто вы столкнулись с проблемами с Python GIL. В этом случае вам может потребоваться переключиться на [многопроцессорную обработку] (https://docs.python.org/3/library/multiprocessing.html#module-multiprocessing). – ekhumoro

+0

Я вижу, что вы добавили еще один код на свой вопрос, но это действительно бесполезно, потому что это не тестовый сценарий. Вы должны * резко * уменьшить количество кода до точки, где вы можете идентифицировать определенные блоки, которые блокируются. Это позволит другим людям запустить ваш тестовый пример и по крайней мере посмотреть, могут ли они воспроизвести проблему. – ekhumoro

+0

Да, после некоторого чтения Я уверен, что вы были правы, что я сталкиваюсь с проблемами с GIL из-за того, чего я пытаюсь достичь в subthread, так что до сих пор был успешным с многопроцессорной обработкой – user2145312

ответ

1

вопрос вы испытываете, что функция, которую вы подключаются к сигналу started, который не запускается в потоке, он запускается в контексте того, где он был установлен, что, по-видимому, является вашим потоком пользовательского интерфейса.

Обычно вы хотите создать пользовательский класс, который наследует от QThread, и любой код, который вы хотите быть выполнены бы в run() функции этого класса. Как так:

class MyTask(QThread): 
    def __init__ (self): 
    QThread.__init__(self) 

    def run(self): 
    print("Code to run in the thread goes here.") 

Если это кажется излишним можно просто установить значение self.cipher_thread.run к вашей собственной функции. Вот пример:

import time 
from PySide.QtCore import QThread 
from PySide import QtGui 

app = QtGui.QApplication("") 

def main(): 
    task = SomeTask() 
    thread = QThread() 

    # Just some variables to pass into the task 
    a, b, c = (1, 2, 3) 
    thread.run = lambda: task.runTask(a, b, c) 


    print("Starting thread") 
    thread.start() 

    # Doing this so the application does not exit while we wait for the thread to complete. 
    while not thread.isFinished(): 
    time.sleep(1) 

    print("Thread complete") 

class SomeTask(): 
    def runTask(self, a, b, c): 
    print a, b, c 
    print("runTask Started") 
    time.sleep(5) 
    print("runTask Complete") 


if __name__ == "__main__": 
    main() 
+0

Хотя я согласен, это приведет к подходящий результат, не широко ли он признан неправильным использованием QThread - https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/ – user2145312

+0

интересная статья Я нашел - http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-1/ ... возможно, не так «неверно» – user2145312

+0

Интересные статьи, спасибо за их размещение. Любая удача, чтобы заставить его работать? – smont

0

Как предложил Эхуморо, у меня возникали проблемы с GIL. использование модуля Multiprocessing работало для меня.

Смежные вопросы