<li>切换较低的细节版本以替换远处的对象。</li> 为什么“进口”不好?

建议不要在 Python 中使用 import *

  • 冒名顶替者。就像 LOD 一样,甚至不是一个物体,只是一张图片或“广告牌”。
  • SIMD.
  • 有人能告诉我为什么吗,这样我下次就不会这样了?

    72569 次浏览
  • 严格来说,这也会是一个演示给他/她的经理,但同样的驱动器在这里将是时间和/或视觉质量。
  • 哎呀!

    Http://docs.python.org/tutorial/modules.html

    我知道这个问题很老了,但是没有人提到 VSync 真是令人兴奋! ! ! ? ?

    您比较了游戏在60fps 时的 CPU 使用率和茶壶演示在60fps 时的 CPU 使用率。

    请注意,一般来说,从模块或包导入 *的做法是不允许的,因为它经常导致 可读性差的代码

    这不是很明显吗,这两个运行(或多或少)在正好60 fps? 这导致了答案..。

    这是因为您正在污染名称空间。您将导入自己名称空间中的所有函数和类,这可能与您自己定义的函数冲突。

    两个应用程序都启用了 vsync!这意味着(简化)渲染帧率被锁定到监视器的“垂直空白间隔”。图形硬件(和/或驱动程序)将只在最大值呈现。60帧/秒。60fps = 60Hz (Hz = 每秒)刷新率。所以你可能使用一个相当旧的,闪烁的 CRT 或者一个普通的 LCD 显示器。在100Hz 运行的 CRT 上,你可能会看到高达100Hz 的帧率。VSync 也以类似的方式应用于 LCD 显示器(它们通常有60Hz 的刷新率)。

    此外,我认为使用限定名对于维护任务来说更加清晰; 您可以在代码行本身看到函数来自哪里,因此可以更容易地检查文档。

    模组 foo:

    def myFunc():
    print 1
    

    因此,茶壶演示可能实际上运行效率更高!如果它使用了30% 的 CPU 时间(相比之下,GTA IV 使用了50% 的 CPU 时间) ,那么它每帧使用的 CPU 时间可能更少,只是等待下一个垂直空白时间间隔的时间更长。要比较两个应用程序,您应该禁用 vsync 并再次测量(您将为两个应用程序测量更高的 fps)。

    有时禁用 vsync 是可以的(大多数游戏在其设置中都有一个选项)。有时候,当 vsync 被禁用时,您会看到“撕裂工件”。

    在您的代码中:

    from foo import *
    
    
    def doThis():
    myFunc() # Which myFunc is called?
    
    
    def myFunc():
    print 2
    

    一个像 GTA IV 这样的大型 PC 游戏怎么可能使用我50% 的 CPU 并以60fps 的速度运行,而一个旋转的 Teapot@60fps 的 DX 演示却使用了高达30% 的 CPU?

    假设。代码根据游戏的不同被编译成字节码或者直接编译成机器码。此外,对象渲染和打包的形式下,一个网格和物体,如纹理,照明和阴影是预先计算,而作为一个纯粹的3D 动画需要这一点,这实时。当游戏实际运行时,还有一些优化,比如只渲染对象的可见部分,只有在关闭时才显示纹理细节。最后,视频游戏的设计很可能是为了在给定的时间内充分利用平台(例如: Intelx86 MMX/SSE,DirectX,...)。

    虽然 GTA 很可能比 DX 演示更有效率,但这种方式测量 CPU 效率基本上是不成立的。效率可以被定义,例如,你在给定的时间里做了多少工作。一个简单的反例: 为每个逻辑 CPU 生成一个线程,并让一个简单的无限循环在其上运行。您将获得100% 的 CPU 使用率,但是它并不高效,因为没有完成任何有用的工作。

    优化游戏的所有方面(现在通常也包括多核心优化)。至于 DX 演示,它的重点不是运行速度快,而是演示概念。

    显式比隐式好。

    不能反驳吧?

    我认为你应该看看 使用图形处理器而不是 CPU... 我打赌图形卡在 GTA IV 比在茶壶样品繁忙得多(它应该实际上是空闲的)。

    像这样的显示器来检查:

    Http://downloads.guru3d.com/rivatuner-gpu-monitor-vista-sidebar-gadget-download-2185.html

    也许你可以用这个显示器来检查一下:

    Http://downloads.guru3d.com/rivatuner-gpu-monitor-vista-sidebar-gadget-download-2185.html

    此外,帧率是一些考虑,也许茶壶样本运行在全速(可能1000 fps)和大多数游戏是限制刷新频率的显示器(约60 fps)。

    假设在一个名为 foo 的模块中有以下代码:

    import ElementTree as etree
    

    尽管给出了所有有保留的和好的答案,但仍然缺少一个重要的答案: Windows 的 CPU 利用率计数器不是很可靠。我猜想这个简单的茶壶演示只是在它的空闲循环中调用呈现函数,在缓冲区交换处阻塞。

    然后在你自己的模块里,你有:

    from lxml import etree
    from foo import *
    

    现在有了一个难以调试的模块,看起来像中有 lxml 的树,但实际上有 ElementTree。

    进程,但不知道如何使用这个 CPU 时间

    Sleep(0);
    

    现在,Windows CPU 利用率计数器只查看每个进程中花费了多少 CPU 时间,而不查看如何使用这些 CPU 时间。试着添加一个

    Sleep(0);
    

    返回,然后比较。

    当然,由于这是 python ——可以随意打破规则并进行探索——但是要警惕那些可能增长十倍的项目,如果源代码缺乏规则,那将是一个问题。

    查看 vsync 上的答案; 这就是为什么它们以相同的帧速率运行。

    其次,CPU 在游戏中失去了领先优势。一个简单的解释是,主要的游戏循环只是一个无限循环:

    while(1) {
    update();
    render();
    }
    

    这些都是好答案。我要补充的是,在教新人用 Python 编写代码时,处理 import *是非常困难的。即使你或者他们没有编写代码,它仍然是一个绊脚石。

    即使你的游戏(或者在这种情况下,茶壶)没有做很多事情,你仍然在你的循环中消耗 CPU。

    我教孩子们(大约8岁)用 Python 编程来操作 Minecraft。我喜欢为他们提供一个有用的编码环境(原子编辑器) ,并教授 REPL 驱动的开发(通过 Bpython)。在 Atom 中,我发现提示/补全的工作效率和 bpython 一样高。幸运的是,与其他一些统计分析工具不同,Atom 没有被 import *愚弄。

    GTA 中50% 的 CPU 比演示中的30% “更有效率”,因为它很可能根本没有做什么; 但是 GTA 正在更新大量的细节。即使添加一个“睡眠(10)”的演示可能会下降它的 CPU 吨。

    最后看看 GPU 的使用情况。演示可能采取 < 1% 的现代视频卡,而 GTA 可能会采取大多数在游戏玩。

    简而言之,您的基准和测量并不准确。

    然而,让我们拿这个例子... 在 这个包装纸他们 from local_module import *一束模块包括 这份街区清单。让我们忽略名称空间冲突的风险。通过做 from mcpi.block import *,他们使这个模糊类型的块的整个列表的东西,你必须去看看,以了解什么是可用的。如果他们使用的是 from mcpi import block,那么您可以键入 walls = block.,然后会弹出一个自动完成列表。 Atom.io screenshot

    如果您在不同的模块中有相同的变量,并且您不想导入整个模块,那么您甚至可以:

    from module1 import b as mod1b
    from module2 import b as mod2b
    
  • 如果我使用 from const import SOMETHING_A, SOMETHING_B ...,那么显然它太冗长了,并且违背了结构化的目的。
  • 因此我觉得在这种情况下,做 from const import *可能是一个更好的选择。
  • 如果有人知道如何重新加载载有“从模块导入 *”的模块,请发帖。否则,这将是避免使用这种形式的另一个原因:

    from module import *
    
    提出它想要的(调试等)。

    delete[]运算符用于删除数组。delete运算符用于删除非数组对象。它分别调用 operator delete[]operator delete函数来删除数组或非数组对象在(最终)调用数组元素或非数组对象的析构函数后所占用的内存。

    以下是这两者之间的关系:

    typedef int array_type[1];
    
    
    // create and destroy a int[1]
    array_type *a = new array_type;
    delete [] a;
    
    
    // create and destroy an int
    int *b = new int;
    delete b;
    
    
    // create and destroy an int[1]
    int *c = new int[1];
    delete[] c;
    
    
    // create and destroy an int[1][2]
    int (*d)[2] = new int[1][2];
    delete [] d;
    

    对于创建非数组对象的 new,它将在元素的类或全局作用域中查找 operator new。它传递所请求的内存量(确切地说,始终是 sizeof(T))。

    对于 delete[],它查看数组的元素类类型并调用它们的析构函数。使用的 operator delete[]函数是元素类型的类中的函数,如果没有,则在全局作用域中使用。

    对于创建数组的 new(即应用于数组类型结构的 new type[]new) ,Standard 将在数组的元素类型类或全局作用域中查找 operator new[],并传递所请求的内存量。如果需要,它可能会请求比 N * sizeof(ElementType)更多的内容(例如,存储元素的数量,这样以后在删除时就知道要执行多少析构函数调用)。如果类声明一个 operator new[],除了接受另一个 size_t的内存数量之外,第二个参数将接收分配的元素数量——它可以使用这个参数来实现它想要的任何目的(调试等等)。.).

    对于创建非数组对象的 new,它将在元素的类或全局作用域中查找 operator new。它传递所请求的内存量(确切地说,始终是 sizeof(T))。

    对于 delete[],它查看数组的元素类类型并调用它们的析构函数。使用的 operator delete[]函数是元素类型的类中的函数,如果没有,则在全局作用域中使用。

    对于 delete,如果传递的指针是实际对象类型的基类,则基类必须具有虚析构函数(否则,行为未定义)。如果它不是基类,则调用该类的析构函数,并使用该类或全局 operator delete中的 operator delete。如果传递了基类,则调用实际对象类型的析构函数,并使用在该类中找到的 operator delete,或者如果没有,则调用全局 operator delete。如果类中的 operator delete有第二个类型为 size_t的参数,它将接收要释放的元素数。

    这是分配/DE 分配模式在 c + + 中的基本用法

    正如文档中建议的那样,您应该(几乎)永远不要在生产代码中使用 import *

    malloc/freenew/deletenew[]/delete[]

    模组导入 *是不好的,而从 从 < em > 包 导入 * 导入 *可能更糟。

    我们需要相应地使用它们。但是,我想补充这个特殊的理解之间的差异 deletedelete[]

    默认情况下,from package import *导入包的 __init__.py所定义的任何名称,包括包的任何子模块(即 由以前的 import语句加载)。

    1) delete用于解除分配给 单一物体的内存

    2) delete[]用于解除分配给 物体数组的内存

    class ABC{}
    
    
    ABC *ptr = new ABC[100]
    

    如果一个包的 __init__.py代码定义了一个名为 __all__的列表,那么它就被认为是遇到 from package import *时应该导入的 子模块名称列表。

    当我们说 new ABC[100]时,编译器可以得到需要分配多少对象的信息(这里是100) ,并将为每个创建的对象调用构造函数

    现在考虑这个例子(假设在 sound/effects/__init__.py中没有定义 __all__) :

    # anywhere in the code before import *
    import sound.effects.echo
    import sound.effects.surround
    
    
    # in your module
    from sound.effects import *
    

    但是相应地,如果我们在这种情况下简单地使用 delete ptr,编译器就不会知道 ptr指向了多少个对象,最终只会调用析构函数并删除1个对象的内存(留下调用析构函数并释放剩余的99个对象)。因此会出现内存泄漏。

    最后一个语句将把 echosurround模块导入当前名称空间(可能覆盖以前的定义) ,因为它们是在执行 import语句时在 sound.effects包中定义的。