继续执行时从函数返回

2024-06-16 10:50:10 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在开发一个Django应用程序,我想在第一次创建对象时填充模型中的几个字段。目前,我可以在我的模型的save()例程中这样做:

def save(self, *args, **kwargs):
    file = fileinfo.getfileinfo(self.file_path)
    if not self.file_size:
        self.file_size = file.FileSize
    if not self.file_inode:
        self.file_inode = file.FileInode
    if not self.duration:
        self.duration = file.Duration
    if not self.frame_width:
        self.frame_width = file.ImageWidth
    if not self.frame_height:
        self.frame_height = file.ImageHeight
    if not self.frame_rate:
        self.frame_rate = file.VideoFrameRate
    super(SourceVideo, self).save(*args, **kwargs)

我在一个名为fileinfo的单独模块中创建了一个名为getfileinfo的函数。这就是我函数的一部分:

def getfileinfo(source):
    fstats = os.stat(source)
    info = dict({
        u'FileSize': fstats.st_size,
        u'FileInode': fstats.st_ino
    })
    output = subprocess.Popen(
        [exiftool, '-json', source], stdout=subprocess.PIPE)
    info.update(
        json.loads(output.communicate()[0], parse_float=decimal.Decimal)[0])
    return DotDict(info)

尽管所有这些都很有效,但我希望避免在检索过程由于某种原因而延迟时阻塞保存过程。在对象创建时不需要这些信息,此后不久就可以填充这些信息。我的想法是,我将修改我的函数,以同时接受所讨论的文件路径作为对象的主键。有了这些信息,我可以获得信息,然后作为一个单独的操作更新我的对象条目。你知道吗

比如:

def save(self, *args, **kwargs):
    fileinfo.getfileinfo(self.file_path, self.id)
    super(SourceVideo, self).save(*args, **kwargs)

我想帮助的是如何在函数实际完成之前从函数返回。我想调用函数,然后让它返回什么,只要它被正确调用。但是,该函数应该继续运行,然后在完成后更新其末端的对象。如果我需要澄清什么,请告诉我。还有,这是工作在做吗?你知道吗

谢谢


Tags: 对象函数self信息sizeifsavedef
3条回答

我不知道您的具体案例是否会像这样工作,但我可能会生成一个指向您的super.save的新线程,如下所示:

import threading

#other code here
def save(self, *args, **kwargs):
    fileinfo.getfileinfo(self.file_path, self.id)
    my_thread = threading.Thread(target=super(SourceVideo, self).save,
            args=args, kwargs=kwargs)
    my_thread.start()

这样save将在后台运行,而其余代码将执行。你知道吗

但是,只有在执行过程中save没有阻塞其他地方可能需要的任何数据时,这才有效。你知道吗

在这种情况下,最好使用celery。你知道吗

这使您能够创建将在后台执行的任务,而不阻塞当前请求。你知道吗

在您的示例中,可以使用.save(),创建更新字段的任务,将其推送到芹菜队列,然后将所需的响应返回给用户。你知道吗

我不知道您的要求,但是如果这个操作在保存时占用的时间不可接受,但在访问时占用的时间可接受,我会考虑将FileSizeDurationVideoFrameRate等视为模型的延迟加载属性,假设较长的初始加载时间是较短保存时间的一个不错的权衡。你知道吗

有很多方法可以做到这一点:可以缓存帧速率,例如,在第一次访问时使用the caching framework。如果希望将其存储在数据库中,可以通过property访问帧速率,并在第一次访问时计算它(以及其他值,如果合适),然后将它们存储在数据库中。理论上,这些是文件本身的属性,因此您的接口不应允许更改它们,从而使它们与所引用的文件不同步。按照这些思路,我可能会这样做:

class MyMediaFile(models.Model):
    file = models.FileField()
    _file_size = models.IntegerField(null=True, editable=False)
    _duration = models.IntegerField(null=True, editable=False)
    <... etc ...>

    @property
    def file_size(self):
        if self._file_size:
            return self._file_size
        else:
            self.populate_file_info(self)
            return self._file_size

    def populate_file_info(self):
        < ... do your thing here ... >
        self._file_size = my_calcuated_file_size
        < ... etc ... >

每个property的逻辑可以很容易地分解为一个一般的延迟加载@property,因此不需要为每个样本重复样板文件。你知道吗

相关问题 更多 >