【问题标题】:Huge difference between python and fortran difference for a small program一个小程序的python和fortran差异之间的巨大差异
【发布时间】:2013-06-23 06:34:26
【问题描述】:

我正在读取一个包含 512**3 个数据点的单精度数据的文件。基于一个阈值,我为每个点分配一个 1 或 0 的标志。我编写了两个程序做同样的事情,一个在 fortran 中,另一个在 python 中。但是 fortran 中的一个需要 0.1 秒,而 python 中的一个需要几分钟。正常吗?或者你能指出我的python程序的问题吗:

fortran.f

  program vorticity_tracking

  implicit none

  integer, parameter :: length = 512**3
  integer, parameter :: threshold = 1320.0

  character(255) :: filen
  real, dimension(length) :: stored_data
  integer, dimension(length) :: flag
  integer index

  filen = "vor.dat"

  print *, "Reading the file ", trim(filen)
  open(10, file=trim(filen),form="unformatted",
 &     access="direct", recl = length*4)
  read (10, rec=1) stored_data
  close(10)

  do index = 1, length
     if (stored_data(index).ge.threshold) then
        flag(index) = 1
     else
        flag(index) = 0
     end if
  end do

  stop
  end program

Python 文件:

#!/usr/bin/env python

import struct
import numpy as np

f_type = 'float32'
length = 512**3
threshold = 1320.0
file = 'vor_00000_455.float'

f = open(file,'rb')
data = np.fromfile(f, dtype=f_type, count=-1)
f.close()

flag = []

for index in range(length):
    if (data[index] >= threshold):
        flag.append(1)
    else:
        flag.append(0)

*********编辑******

感谢您的 cmets。我不确定如何在 fortran 中执行此操作。我尝试了以下方法,但这仍然很慢。

 flag = np.ndarray(length, dtype=np.bool)    
 for index in range(length):
     if (data[index] >= threshold):
         flag[index] = 1
     else:
         flag[index] = 0

谁能给我看看?

【问题讨论】:

  • 您是否尝试过预先分配您的标志 []? IE。使用 np.ndarray(5123, dtype=np.bool) 而不是列表。数组具有随机访问权限,因此您需要 O(1) 时间来访问(整个周期需要 O(n) 时间),而对于列表,您需要 O(n) 时间来访问 1 个元素(并且 O(n2)完全)。
  • 这是正常的。 Python 通常比 Fortran 之类的编译语言慢得多(但更灵活)。对于这样的计算,您可以尝试 numpy 的高级功能(但我错问细节)。
  • @AlexanderMihailov 感谢您的评论。但我不确定如何实施您的建议。我已经编辑了我的帖子以说明我尝试过的内容,但它并没有改变性能。
  • 我建议您谨慎对待您正在尝试做的事情。当然,您总是可以将 python 代码优化到极致(在极端情况下,它永远不会像 Fortran 一样快——如果您想知道为什么,那是另一个问题)。但是在那些极端情况下……您首先会失去很多使用 python 的优势;它的语言范式以自己独特的方式使代码更具表现力。当您与该语言的设计使用方式作斗争时,您应该考虑使用专门针对您的需求而设计的其他语言。

标签: python fortran


【解决方案1】:

您的两个程序完全不同。您的 Python 代码反复更改结构的大小。您的 Fortran 代码没有。您不是在比较两种语言,而是在比较两种算法,其中一种显然是劣等的。

【讨论】:

  • 感谢@David 的评论,但我不确定如何在 python 中执行此操作。有什么建议吗?
【解决方案2】:

一般而言,Python 是一种解释型语言,而 Fortran 是一种编译型语言。因此,您在 Python 中有一些开销。但应该不会花那么长时间。

在python版本中可以改进的一点是用索引操作代替for循环。

#create flag filled with zeros with same shape as data
flag=numpy.zeros(data.shape)
#get bool array stating where data>=threshold
barray=data>=threshold
#everywhere where barray==True put a 1 in flag
flag[barray]=1

更短的版本:

#create flag filled with zeros with same shape as data
flag=numpy.zeros(data.shape)
#combine the two operations without temporary barray
flag[data>=threshold]=1

【讨论】:

  • 谢谢,这非常好用。你能解释我一件事吗?为什么“flag[data>=threshold]=1”比我写一个像“for i in range(length): if (data[i]>=threshold): flag[i]=1”这样的循环快得多“?
  • 我真的不知道,所以我只能猜测。我认为有两个原因。 Numpy 使用了大量的 c 代码并且它使用向量化。
【解决方案3】:

在 python 上试试这个:

flag = data > threshhold

它会给你一个你想要的标志数组。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-28
    • 1970-01-01
    • 2017-06-15
    • 1970-01-01
    相关资源
    最近更新 更多