Discuz! BBS

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 338|回复: 2

Python与 Delphi共享数据

[复制链接]

254

主题

363

帖子

2431

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2431
发表于 2025-3-2 11:16:40 | 显示全部楼层 |阅读模式
使用内存映射文件(适用于Windows)
这种方法通过Windows API来实现,允许两个应用程序共享内存中的数据块。这种方法在性能上非常高效,但需要Windows平台支持,并且需要处理同步问题以避免竞争条件。在Delphi中可以使用TMemoryMappedFile类来实现。在Python中,可以使用mmap模块或者memory_fs库(如pywin32)。然而,对于跨平台的需求,这种方法可能不是最佳选择。对于跨平台需求,通常推荐使用数据库或网络通信方法。

选择哪种方法取决于你的具体需求,如数据量大小、实时性要求、是否需要跨平台以及系统的复杂性等因素。通常,对于大多数项目,使用数据库或文件共享就
  1. import mmap
  2. import contextlib
  3. ####################################
  4. # to clear share data file with \x00
  5. ####################################
  6. def cleanShareFile(fName):
  7.         with open(fName, "wb") as f:
  8.                         fill = '\x00' * 1024
  9.                         fill = fill.encode(encoding='utf-8')  # turns str to bytes and write to file.
  10.                         f.write(fill)  # turns str to bytes and write to file.
  11.                         f.close()
  12. ####################################
  13. # write money data to data file
  14. ####################################
  15. def writeDataToShareFile(fName, money_dictionary):
  16.         with open(fName,'r+b') as f:   
  17.                 with contextlib.closing(mmap.mmap(f.fileno(), 1024, access=mmap.ACCESS_WRITE)) as m:
  18.                         try:
  19.                                 m.seek(0)
  20.                                 outp_string = 'Pufa:' + str(money_dictionary['pufa']) + \
  21.                                                         '|Lingqian:' + str(money_dictionary['lingqian']) + \
  22.                                                         '|Qita:' + str(money_dictionary['qita'])
  23.                                 outp_string.rjust(1024, '\x00')  # 右对齐outp_string为\x00
  24.                                 outp_bytes = outp_string.encode(encoding='utf-8')  # 将str类型转变为bytes类型
  25.                                 m.write(outp_bytes)
  26.                                 m.flush()
  27.                                 print(u"写入成功!")
  28.                         except Exception as err:
  29.                                 print('!'*10 + repr(err))  # 获取完整的err信息。
  30.                         # m.close()
  31.                 f.close()

  32. ####################################
  33. # main flow 输入数字并存储于共享数据文件
  34. ####################################
  35. print(u"请输入数字:")
  36. lingqian = input(u"微信零钱:")
  37. pufa = input(u"浦发:")
  38. qita = input(u"其他零钱:")
  39. money_diction={'lingqian':lingqian, 'pufa':pufa, 'qita':qita}

  40. fName = ".\money.dat"
  41. cleanShareFile(fName)
  42. writeDataToShareFile(fName, money_diction)
复制代码
  1. import mmap
  2. import contextlib
  3. ####################################
  4. # Get content of share file as string
  5. ####################################
  6. def getShareFileContent():
  7.         fName = "./money.dat"
  8.         text = None
  9.         with open(fName,'r') as f:   
  10.                 with contextlib.closing(mmap.mmap(f.fileno(), 1024, access=mmap.ACCESS_READ)) as m:
  11.                         text = m.read(1024)
  12.                         text = str(text, encoding='utf-8').replace('\x00', '')
  13.                         m.close()
  14.                 f.close()
  15.         return text
  16. ####################################
  17. # return:{Pufa:100, Lingqian:100, Qita:100}
  18. ####################################
  19. def getMoney():
  20.         dic = {}
  21.         text = getShareFileContent()
  22.         ls = text.split("|")
  23.         for item in ls:
  24.                 key, value = item.split(":")
  25.                 dic[key] = value
  26.         return dic
复制代码


回复

使用道具 举报

254

主题

363

帖子

2431

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2431
 楼主| 发表于 2025-3-17 23:57:45 | 显示全部楼层
2.1 cleanShareFile(fName)
此函数用于清除指定名称的共享数据文件的内容。它首先以二进制写入模式打开文件,然后创建一个由1024个\x00字符组成的字符串(代表空字符),并将其编码为字节类型后写入文件。这样,文件的前1024个字节将被\x00填充,从而达到清除文件内容的目的。

注意:函数中的fill = fill.encode(encoding='utf-8')是多余的,因为fill已经是一个字节字符串(bytes),不需要再次编码。

2.2 writeDataToShareFile(fName, money_dictionary)
此函数用于将金钱数据写入共享数据文件。它首先以二进制读写模式打开文件,然后使用mmap模块将文件的前1024个字节映射到内存中。接下来,函数构建一个包含金钱数据的字符串,并将其右对齐到1024个字符宽度,不足部分用\x00填充。然后,将这个字符串编码为字节类型并写入映射的内存区域。最后,刷新内存映射并关闭映射和文件。
回复

使用道具 举报

254

主题

363

帖子

2431

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2431
 楼主| 发表于 2025-3-18 00:22:48 | 显示全部楼层
mmap加锁和解锁
在使用mmap模块进行内存映射文件操作时,加锁和解锁是一个重要的考虑因素,特别是在多线程或多进程环境中。加锁可以确保在特定时间段内只有一个线程或进程能够访问映射区域,从而避免数据竞争和不一致的问题。

1. 使用mmap.flock进行加锁和解锁
在mmap模块中,mmap.mmap对象提供了一个flock方法,用于对映射区域进行加锁和解锁操作。flock方法可以接受一个mmap.LOCK_*标志来指定要执行的锁操作:

mmap.LOCK_SH: 共享锁。允许多个进程同时读取映射区域,但不允许写入。

mmap.LOCK_EX: 排他锁。只允许一个进程访问映射区域,无论是读取还是写入。

mmap.LOCK_UN: 解锁。释放之前获得的锁。

  1. import mmap
  2. import os

  3. # 打开一个文件并进行内存映射
  4. with open('example.txt', 'r+') as f:
  5.     mm = mmap.mmap(f.fileno(), 0)  # 映射整个文件
  6.    
  7.     # 对映射区域加排他锁
  8.     mm.flock(mmap.LOCK_EX)
  9.    
  10.     # 在这里执行需要加锁的操作,例如写入数据
  11.     mm.write(b'Hello, mmap!')
  12.    
  13.     # 解锁
  14.     mm.flock(mmap.LOCK_UN)

  15. # 关闭内存映射对象
  16. mm.close()
复制代码


在这个示例中,我们首先打开一个文件并进行内存映射。然后,我们使用flock方法加上一个排他锁,以确保在写入数据时没有其他进程可以访问映射区域。完成写入操作后,我们释放锁以允许其他进程访问映射区域。

注意事项
锁的范围:flock锁是作用于整个映射文件的,而不是映射区域的一部分。因此,即使你只映射了文件的一部分,锁也会影响整个文件。

锁的继承性:在某些操作系统上,flock锁可能不会在fork后被子进程继承。这可能会影响多进程程序的行为。

锁的兼容性:flock锁与文件系统的锁机制紧密相关,因此可能受到文件系统类型和配置的影响。

2. 使用其他同步机制
除了mmap.flock之外,你还可以考虑使用其他同步机制来保护对映射区域的访问,例如Python的threading模块中的锁或条件变量,或者multiprocessing模块中的同步原语。这些同步机制提供了更细粒度的控制和更广泛的适用性,但也可能需要更多的设置和管理工作。

在选择同步机制时,你应该根据具体的应用场景和需求来决定使用哪种机制。如果你只需要简单的文件级锁定,并且操作系统支持flock锁,那么mmap.flock可能是一个简单而有效的选择。如果你需要更复杂的同步逻辑或跨进程的同步,那么可能需要考虑其他同步机制。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|DiscuzX

GMT+8, 2025-4-16 04:45 , Processed in 0.015018 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表