Python for循环中的线程

1 投票
1 回答
1188 浏览
提问于 2025-04-17 16:35

我正在写一个Python脚本,这个脚本可以从一个API获取信息,并创建一个上下文菜单,让你可以访问这些信息。因为调用API的时候速度有点慢,所以我想用线程来加快速度,但我不太确定怎么在我的代码中实现线程。我在这个网站上查找线程的相关资料:http://www.ibm.com/developerworks/aix/library/au-threadingpython/。我理解代码的逻辑,只是不想为每一个想要使用线程的方法都写一个线程类。

这是创建上下文菜单的类,然后解析返回的json数据。我觉得我应该把它加到run命令的for循环里。非常感谢任何帮助。

class SyncsnippetsCommand(sublime_plugin.TextCommand):

  def __init__(self, queue):
      threading.Thread.__init__(self)
      self.queue = queue

  def buildLexerDict(self,snippets):
      lexers = snippets[0]['user']['lexers']
      lexer_dict = {}
      for lexer in lexers:
          lexer_dict[lexer] = []
      return lexer_dict

  def buildsnippetsContextDict(self,snippets,lexer_dict):
      snippets_dict = lexer_dict
      for snippet in snippets:
          snippets_dict[snippet['lexer']].append({"id":str(snippet['id']),
                                         "title":snippet['title']})
      return snippets_dict

  def run(self, edit):
      snippet_url = buildsnippetURL()
      snippets_count = 1;
      snippets = getsnippets(snippet_url)
      context_menu = '['
      context_menu += '\n\t{ "caption": "snippets", "id": "file", "children":'
      context_menu += '\n\t\t['
      if snippets == None:
          {"caption":"No snippets available"}
      else:
          snippets = snippets['objects']
          lexers = self.buildLexerDict(snippets)
          snippets_dict = self.buildsnippetsContextDict(snippets, lexers)
          for j,key in reversed(list(enumerate(reversed(snippets_dict.keys())))):
              ... loop through JSON and create menu ...
              if j == 0:
                  context_menu += ''
              else:
                  context_menu += ',' 
      context_menu += '\n\t\t]'
      context_menu += '\n\t}'
      context_menu += '\n]'
      f = open(sublime.packages_path() + '\snippetSync\\Context.sublime-menu', 'w')
      f.write(context_menu)
      f.close
      self.view.set_status('snippet', 'snippet Sync: Added ' + str(snippets_count) + ' snippets from your account.')
      sublime.set_timeout(lambda: self.view.erase_status('snippet'), 3000)
      return

1 个回答

2

这是一个简单的Sublime Text 2插件,里面用到了线程。它的功能是在3秒后插入Hello World!。你会发现,在这3秒钟内,你仍然可以移动光标。

在你的情况下,看起来你只需要从一个API获取一堆代码片段,然后根据返回的数据创建一个上下文菜单。接着,底部会有一个通知告诉你添加了多少个代码片段。我可能理解错了,但你应该可以修改这段代码,让你的插件正常工作。

import threading
import time
import sublime
import sublime_plugin

"""
The command just creates and runs a thread.
The thread will do all the work in the background.

Note that in your Thread constructor, you will need to pass in an 
instance of your Command class to work with in your thread.
"""
class ExampleCommand(sublime_plugin.TextCommand):

    def run(self, edit):

        exampleThread = ExampleThread(self, edit)
        exampleThread.start()

"""
Extend the Thread class and add your functionality in 
the run method below.

One thing to remember when moving your code over is 
you need to use self.cmd instead of self.
"""
class ExampleThread(threading.Thread):

    """
    Remember to pass in the parameters you need
    in this thread constructor.
    """
    def __init__(self, cmd, edit):
        threading.Thread.__init__(self)
        self.cmd = cmd
        self.edit = edit

    """
    Add your functionality here.

    If you need to access the main thread, you need to
    use sublime.set_timeout(self.callback, 1).

    In my example here, you can't call insert text into the editor
    unless you are in the main thread.

    Luckily that is fast operation.

    Basically, time.sleep(3) is a slow operation and will block, hence it
    is run in this separate thread.
    """
    def run(self):
        time.sleep(3)
        sublime.set_timeout(self.callback, 1)

    """
    This is the callback function that will be called to 
    insert HelloWorld. 

    You will probably need to use this to set your status message at 
    the end. I'm pretty sure that requires that you be on main thread 
    to work.
    """
    def callback(self):
        self.cmd.view.insert(self.edit, 0, "Hello, World!")

更新

我找了一些时间,按照我之前提到的方法,把你的代码片段整合进来了。你还需要填补一些空白,但希望这能给你一个关于代码放置位置的想法。我测试了基本的框架仍然可以正常工作,所以在这个例子中,构建上下文菜单的部分被注释掉了。

import threading
import time
import sublime
import sublime_plugin


def buildsnippetURL():
    return ""

def getsnippets(snippet_url):
    time.sleep(3)
    return ""

class SyncsnippetsCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        syncsnippetsThread = SyncsnippetsThread(self, edit)
        syncsnippetsThread.start()


class SyncsnippetsThread(threading.Thread):
    def __init__(self, cmd, edit):
        threading.Thread.__init__(self)
        self.cmd = cmd
        self.edit = edit

    def buildLexerDict(self,snippets):
        lexers = snippets[0]['user']['lexers']
        lexer_dict = {}
        for lexer in lexers:
            lexer_dict[lexer] = []
        return lexer_dict

    def buildsnippetsContextDict(self,snippets,lexer_dict):
        snippets_dict = lexer_dict
        for snippet in snippets:
            snippets_dict[snippet['lexer']].append({"id":str(snippet['id']),
                                         "title":snippet['title']})
        return snippets_dict

    def run(self): 
        snippet_url = buildsnippetURL()
        snippets_count = 1;
        snippets = getsnippets(snippet_url)

        """
        context_menu = '['
        context_menu += '\n\t{ "caption": "snippets", "id": "file", "children":'
        context_menu += '\n\t\t['
        if snippets == None:
            {"caption":"No snippets available"}
        else:
            snippets = snippets['objects']
            lexers = self.buildLexerDict(snippets)
            snippets_dict = self.buildsnippetsContextDict(snippets, lexers)
            for j,key in reversed(list(enumerate(reversed(snippets_dict.keys())))):
                ... loop through JSON and create menu ...
                if j == 0:
                    context_menu += ''
                else:
                    context_menu += ',' 
        context_menu += '\n\t\t]'
        context_menu += '\n\t}'
        context_menu += '\n]'
        f = open(sublime.packages_path() + '\snippetSync\\Context.sublime-menu', 'w')
        f.write(context_menu)
        f.close
        """

        sublime.set_timeout(lambda: self.callback(snippets_count), 1)

    def callback(self, snippets_count):
        self.cmd.view.set_status('snippet', 'snippet Sync: Added ' + str(snippets_count)  + ' snippets from your account.')
        sublime.set_timeout(lambda: self.cmd.view.erase_status('snippet'), 3000)

撰写回答