gpt4 book ai didi

python - Python [de]压缩模块在Linux上是线程安全的吗?在Google App Engine上?

转载 作者:太空宇宙 更新时间:2023-11-03 15:29:11 25 4
gpt4 key购买 nike

我应该使用哪个压缩解压缩Python模块来构建一个系统,在该系统中Google App Engine(Python 2.7)与Linux机器上的应用程序交换压缩数据?

还有两个附加约束:

  • Linux机器和GAE都将进行压缩/解压缩,并且需要安全地运行线程。
  • 我想做所有事情而无需使用类似文件的对象,因为App Engine无法为动态文件提供常规的Python文件名。

  • 我问是因为从文档中尚不清楚某些[de]压缩模块是否是线程安全的。

    有人可以帮忙填写压缩模块表吗?
  • bz2:是安全的,每个:http://docs.python.org/2/library/bz2.html,但是有关于单个锁定的注释,这使我想知道是否需要显式管理锁定。
  • zlib :? -释放GIL,每个:http://docs.python.org/2/c-api/init.html
    但是据说底层的C代码是安全的:http://www.gzip.org/zlib/zlib_faq.html#faq21
  • gzip :?
  • lzma:不安全,每个:http://docs.python.org/3.4/library/lzma

  • 谢谢!

    编辑(针对abarnert的问题):
  • RAM与类似文件的对象= App Engine没有提供打开类似文件的对象的方法(除非文件是作为应用程序的一部分上传的)。因此,如果GAE从Linux盒中获取压缩数据,那么如果压缩模块坚持要我通过类似文件的对象,那么我不知道一种解压缩数据的方法。例如,gzip模块坚持使用文件名:http://docs.python.org/2/library/gzip.html
  • 在Linux上为“线程安全” =应用程序将位于Web服务器之后,因此很可能会同时调用单独的线程进行压缩和/或解压缩。 Linux应用程序首先从磁盘上读取数千个(几百万个)压缩数据的半随机块,然后解压缩每个块,然后更改每个未压缩的块,然后压缩更改后的块,然后发送到GAE。目前,该应用程序使用zlib并在Cherrypy的轻负载下完美运行,但是一旦请求开始并行发生,就会引发zlib错误。解决此压缩问题后,我将立即切换到nginx。
  • 最佳答案

    您的问题基本上是没有意义的,因为您误解了一些基本的东西并产生了不存在的问题。我尝试在评论中回答,但是您可以这样做的方式是有局限性的,所以…

    I want to do everything without using file-like objects, because App Engine cannot provide conventional Python filenames for dynamic files.



    对于类似文件的对象,您不需要文件名或文件。这就是类文件对象背后的全部想法。

    App Engine does not provide a way to open a file-like object (unless the file was uploaded as part of the app).



    不,您仍在混淆文件对象和类似文件的对象。 file object代表磁盘上的实际文件。 GAE限制了这些。类似于文件的对象是具有相同API的任何对象,即,一个行为类似于文件的对象,而实际上(不一定)是一个对象。 GAE不会采取任何措施来阻止您创建类似文件的对象。

    --

    类似于文件的对象 StringIO.StringIO 的范例示例的行为类似于文件对象,但是它不是读写文件,而是读写内存中的字符串缓冲区。

    因此,您可以打开一个类似文件的对象来编写,如下所示:
    my_file_like_obj = StringIO()

    或者,如果您的内存中有缓冲区,并且希望能够像文件一样从中读取:
    my_file_like_obj = StringIO(buffer)

    但是,在许多情况下,Python/GAE已经为您提供了一个文件状对象,您可以按原样使用它,而无需将其读入缓冲区并将其包装在另一个文件状对象中。许多联网API都给您提供类似文件的对象,但不是全部。

    例如,如果您调用 urllib2.urlopen,则结果是一个类似文件的对象。如果您调用 urlfetch.fetch,则不会,因此,如果需要,则必须使用 StringIO(response.content)

    So if GAE gets compressed data from the Linux box, I don't know of a way to uncompress it if the compression module insists that I go through a file-like object.



    如果它坚持使用类似文件的对象,则为其提供类似文件的对象。创建实际文件是一种方法,但不是唯一的方法。如果您收到了 urllib2.urlopen响应,只需传递该响应即可。如果您的内存中有缓冲区,只需将其包装在 StringIO中即可。等等。

    The gzip module, for example, insists on having a filename: http://docs.python.org/2/library/gzip.html



    不,不是。阅读您链接到的文档:

    class gzip.GzipFile([filename[, mode[, compress level[, fileobj[, mtime]]]]])



    注意,是否有一个 fileobj参数和一个 filename参数?并且文档的第一行说:

    … At least one of fileobj and filename must be given a non-trivial value …



    因此,除非 filenamefileobj,否则它不必坚持使用 None。要解决此问题,只需…不要将 None传递给 fileobj
    fileobj是否必须是真实的文件对象,还是可以是另一个类似于文件的对象?好吧,下一段说:

    … The new class instance is based on fileobj, which can be a regular file, a StringIO object, or any other object which simulates a file.



    所以,你去了。

    不幸的是,Python 2.x对于像文件一样的对象并不是100%一致的,并且文档并不总是很清楚。 (在3.x中已对此进行了很多清理,但是如果您使用的是GAE,那对您没有任何好处。)

    如果某些API因为不能充分模拟API而不喜欢您的文件状对象,则可以通过获取 AttributeError来查找。例如,您可能会收到一条错误消息,说明您从 urllib2.urlopen取回的对象没有 seek属性。

    解决方法很简单:将其读入内存并创建 StringIO。换句话说,只需将 fileobj=my_file_obj更改为 fileobj=StringIO(my_file_obj.read())即可。

    还要注意, GzipFile本身就是一个类似文件的对象。这很重要,因为这意味着您可以将事物链接在一起-您可以使用 GzipFile生成 StringIO,然后使用 TarFile生成 GzipFile,依此类推。

    "Thread-safe" on linux = Application will be behind a webserver, and so separate threads will be likely be called upon to compress and/or decompress at the same time.



    那不是问题。同样,请阅读链接到的文档:

    if you need to use a single LZMAFile instance from multiple threads, it is necessary to protect it with a lock.



    压缩和/或解压缩多个独立的 LZMAFile实例不是问题。仅当您要在线程之间共享同一实例时。而且几乎从来没有这样做的充分理由。

    The Linux app starts by reading a few thousand (out of many million) semi-random chunks of compressed data from disk, then uncompressing each, then altering each uncompressed chunk, then compressing the altered chunks, then sending to GAE.



    您正在谈论的所有压缩机都是流压缩机。您不能在不压缩文件的情况下从文件中间解压缩任意块。

    对我而言,这意味着您实际拥有的是一堆独立压缩的块(无论是在单独的文件中,还是串联到单个文件中,目前尚不清楚,但这并不重要)。

    这意味着您无需在任何地方共享解压缩器或压缩器。例如:
    with lzma.LZMAFile(chunk_path) as f:
    decompressed_chunk = f.read()
    new_chunk = alter(decompressed_chunk)
    sio = StringIO.StringIO()
    with lzma.LZMAFile(fileobj=sio) as f:
    f.write(new_chunk)
    compressed_chunk = sio.getvalue()
    send_to_gae(compressed_chunk)

    线程之间没有共享的内容。即使200个线程同时执行此操作,即使其中100个线程正在尝试处理同一块文件,也不会有问题。唯一需要排序的是最后的 send_to_gae

    Right now, the app uses zlib and runs flawlessly under light load within cherrypy, but raises zlib errors as soon as requests start happening in parallel.



    在不了解您的代码的情况下,很难对其进行调试,但是我有一个很好的猜测:您通过写入临时文件来进行压缩,而不是使用 tempfile 中的安全API进行了重新发明带有独特错误的轮子,这意味着您最终会被线程覆盖彼此的临时文件。

    what does the comment about individual locking mean with respect to bz2



    诚然,这有点令人困惑。它只说:
  • 线程安全使用单独的锁定机制。

  • 这显然意味着它是线程安全的,但是为什么您要关心它们使用哪种锁定机制?什么是“个人锁定机制”?

    您只能通过查看 the source来辨别。

    它们的意思是每个 BZ2Compressor(和 BZ2Decompressor)对象都有自己单独的锁,因此其中一个可以锁定而不会影响其他对象。

    如果您还没有处理Python C扩展中的线程,那么您可能不明白这是怎么回事。通常,在Python中,每个线程都需要持有 GIL才能执行任何工作,这意味着一次只能运行一个线程。但是C扩展模块可以在处理非Python对象的大量CPU工作时释放GIL(例如,压缩大缓冲区)。如果有N个线程释放GIL,则最多可以并行运行N + 1个线程,这意味着您可以从自己的8核CPU中获得很大的优势,而无需运行多个进程。但是,在释放GIL时,您不能触摸任何Python对象,除非您用锁保护它们。

    许多释放GIL以加速的模块会创建一个模块锁(有时是因为弄清楚代码可能接触的对象不是那么容易)。这意味着您可以同时运行一个执行该模块工作的线程与执行其他操作的线程,但是最多可以运行一个执行该模块工作的线程。

    但是,如果每个线程只需要触摸一个对象,则可以为每个对象使用不同的锁,这意味着您可以并行运行任意多个线程,只要它们都在不同的对象上工作即可。

    如果您确实尝试同时在两个线程中使用同一对象,则它不会破坏任何内容。您将只剩下一个线程等待获取锁,直到另一个线程完成为止(这比等待GIL更好或更糟)。

    关于python - Python [de]压缩模块在Linux上是线程安全的吗?在Google App Engine上?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17180853/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com