aza*_*ias 19 python variables share
以下不起作用
one.py
import shared
shared.value = 'Hello'
raw_input('A cheap way to keep process alive..')
Run Code Online (Sandbox Code Playgroud)
two.py
import shared
print shared.value
Run Code Online (Sandbox Code Playgroud)
在两个命令行上运行:
>>python one.py
>>python two.py
Run Code Online (Sandbox Code Playgroud)
(第二个得到属性错误,这是正确的).
有没有办法实现这一点,即在两个脚本之间共享一个变量?
sda*_*aau 41
希望在这里记下关于这个问题的笔记是可以的.
首先,我很欣赏OP中的示例,因为这也是我开始的地方 - 尽管它让我想到了shared一些内置的Python模块,直到我在模块之间的[Tutor] Global Variables中找到了一个完整的例子?? .
但是,当我寻找"在脚本之间共享变量"(或进程)时 - 除了Python脚本需要使用在其他Python源文件中定义的变量(但不一定是运行进程)的情况 - 我经常偶然发现其他两个用例:
因此,大多数关于"共享变量"和"进程间通信"(IPC)的命中讨论了这两个案例; 然而,在这两种情况下,人们都可以观察到"父母","孩子"通常会有一个参考.
然而,我感兴趣的是运行多个相同脚本的调用,独立运行,以及在单例/单个实例中在Python之间共享数据(如在Python中如何共享对象实例的多个调用)模式.上述两种情况并未真正解决这类问题 - 相反,它本质上简化为OP中的示例(跨两个脚本共享变量).
现在,在Perl中处理这个问题时,有IPC :: Shareable ; "允许您将变量绑定到共享内存",使用"整数或4个字符串[1],作为跨进程空间的数据的公共标识符".因此,没有临时文件,也没有网络设置 - 我认为这对我的用例很有用; 所以我在Python中寻找相同的东西.
然而,正如@Drewfer所接受的回答所指出的那样:" 如果不将信息存储在解释器的两个实例之外的某个地方,你将无法做你想做的事情 "; 换句话说:要么必须使用网络/套接字设置 - 要么必须使用临时文件(ergo,没有共享RAM用于" 完全独立的python会话 ").
现在,即使考虑到这些因素,也很难找到工作示例(除了pickle) - 在mmap和多处理的文档中也是如此.我设法找到了一些其他的例子 - 这些例子也描述了文档没有提到的一些陷阱:
mmap:使用mmap |在两个不同的脚本中共享Python数据的工作代码 schmichael的博客
mmap只是用于访问此临时文件的特殊接口multiprocessing:工作代码:
SyncManager(via manager.start())with shared的工作示例Queue; 服务器写入,客户端读取(共享数据)BaseManager(via server.serve_forever())工作示例; 服务器写入,客户端读取和写入multiprocessing陷阱有很好的解释,并且是SyncManager(通过manager.start())共享字典的一个工作示例; 服务器什么都不做,客户端读写感谢这些例子,我想出了一个例子,它与示例基本相同mmap,使用" 同步python dict "示例的方法 - 使用BaseManager(manager.start()通过文件路径地址)和共享列表; 服务器和客户端读写(粘贴在下面).注意:
multiprocessing经理可以通过manager.start()或启动server.serve_forever()
serve_forever()锁 - start()没有multiprocessing:它似乎可以正常使用start()ed进程 - 但似乎忽略了那些serve_forever()multiprocessing可以是IP(套接字)或临时文件(可能是管道?)路径; 在multiprocessing文档中:
multiprocessing.Manager()- 这只是一个返回a 的函数(不是类实例化)SyncManager,它是一个特殊的子类BaseManager; 和使用start()- 但不是独立运行的脚本之间的IPC; 这里使用了文件路径serve_forever()在独立运行的脚本之间,很少有其他示例用于IPC; 这里使用IP /套接字地址除了" 同步python dict "帖子中的所有陷阱之外,如果列表中还有其他的陷阱.该帖子指出:
dict的所有操作必须用方法完成而不是dict赋值(syncdict ["blast"] = 2会因为多处理共享自定义对象的方式而失败)
dict['key']获取和设置的解决方法是使用dict公共方法get和update.问题是没有这样的公共方法可供选择list[index]; 因此,对于共享的名单中,除了我们要注册__getitem__和__setitem__方法(这是私人的list)的exposed,这意味着我们还必须重新注册所有的公共方法list,以及:/
嗯,我认为这些是最关键的事情; 这些是两个脚本 - 它们可以在不同的终端中运行(服务器优先); 使用Python 2.7在Linux上开发的注释:
a.py (服务器):
import multiprocessing
import multiprocessing.managers
import logging
logger = multiprocessing.log_to_stderr()
logger.setLevel(logging.INFO)
class MyListManager(multiprocessing.managers.BaseManager):
pass
syncarr = []
def get_arr():
return syncarr
def main():
# print dir([]) # cannot do `exposed = dir([])`!! manually:
MyListManager.register("syncarr", get_arr, exposed=['__getitem__', '__setitem__', '__str__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'])
manager = MyListManager(address=('/tmp/mypipe'), authkey='')
manager.start()
# we don't use the same name as `syncarr` here (although we could);
# just to see that `syncarr_tmp` is actually <AutoProxy[syncarr] object>
# so we also have to expose `__str__` method in order to print its list values!
syncarr_tmp = manager.syncarr()
print("syncarr (master):", syncarr, "syncarr_tmp:", syncarr_tmp)
print("syncarr initial:", syncarr_tmp.__str__())
syncarr_tmp.append(140)
syncarr_tmp.append("hello")
print("syncarr set:", str(syncarr_tmp))
raw_input('Now run b.py and press ENTER')
print
print 'Changing [0]'
syncarr_tmp.__setitem__(0, 250)
print 'Changing [1]'
syncarr_tmp.__setitem__(1, "foo")
new_i = raw_input('Enter a new int value for [0]: ')
syncarr_tmp.__setitem__(0, int(new_i))
raw_input("Press any key (NOT Ctrl-C!) to kill server (but kill client first)".center(50, "-"))
manager.shutdown()
if __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud)
b.py (客户)
import time
import multiprocessing
import multiprocessing.managers
import logging
logger = multiprocessing.log_to_stderr()
logger.setLevel(logging.INFO)
class MyListManager(multiprocessing.managers.BaseManager):
pass
MyListManager.register("syncarr")
def main():
manager = MyListManager(address=('/tmp/mypipe'), authkey='')
manager.connect()
syncarr = manager.syncarr()
print "arr = %s" % (dir(syncarr))
# note here we need not bother with __str__
# syncarr can be printed as a list without a problem:
print "List at start:", syncarr
print "Changing from client"
syncarr.append(30)
print "List now:", syncarr
o0 = None
o1 = None
while 1:
new_0 = syncarr.__getitem__(0) # syncarr[0]
new_1 = syncarr.__getitem__(1) # syncarr[1]
if o0 != new_0 or o1 != new_1:
print 'o0: %s => %s' % (str(o0), str(new_0))
print 'o1: %s => %s' % (str(o1), str(new_1))
print "List is:", syncarr
print 'Press Ctrl-C to exit'
o0 = new_0
o1 = new_1
time.sleep(1)
if __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud)
最后一点,在Linux /tmp/mypipe上创建 - 但是是0字节,并且具有属性srwxr-xr-x(对于套接字); 我想这让我感到高兴,因为我既不必担心网络端口,也不担心临时文件:)
其他相关问题:
Dre*_*fer 18
如果不将信息存储在解释器的两个实例外部的某个位置,您将无法执行所需的操作.
如果它只是你想要的简单变量,你可以轻松地将python dict转储到带有pickle模块的文件中,然后在脚本2中重新加载它.例:
one.py
import pickle
shared = {"Foo":"Bar", "Parrot":"Dead"}
fp = open("shared.pkl","w")
pickle.dump(shared, fp)
Run Code Online (Sandbox Code Playgroud)
two.py
import pickle
fp = open("shared.pkl")
shared = pickle.load(fp)
print shared["Foo"]
Run Code Online (Sandbox Code Playgroud)
小智 11
sudo apt-get install memcached python-memcache
one.py
import memcache
shared = memcache.Client(['127.0.0.1:11211'], debug=0)
shared.set('Value', 'Hello')
Run Code Online (Sandbox Code Playgroud)
two.py
import memcache
shared = memcache.Client(['127.0.0.1:11211'], debug=0)
print shared.get('Value')
Run Code Online (Sandbox Code Playgroud)
你在这里尝试做什么(通过单独的python解释器在Python模块中存储共享状态)将不起作用.
模块中的值可以由一个模块更新,然后由另一个模块读取,但这必须在同一个Python解释器中.你在这里做的实际上是一种进程间通信; 这可以通过两个进程之间的套接字通信来完成,但它远远不如你期望在这里工作那么简单.
您可以使用相对简单的mmap文件。您可以使用shared.py存储公共常量。以下代码将在不同的python解释器\脚本\ processes中工作
shared.py:
MMAP_SIZE = 16*1024
MMAP_NAME = 'Global\\SHARED_MMAP_NAME'
Run Code Online (Sandbox Code Playgroud)
*“全局”是Windows全局名称的语法
一个.py:
from shared import MMAP_SIZE,MMAP_NAME
def write_to_mmap():
map_file = mmap.mmap(-1,MMAP_SIZE,tagname=MMAP_NAME,access=mmap.ACCESS_WRITE)
map_file.seek(0)
map_file.write('hello\n')
ret = map_file.flush() != 0
if sys.platform.startswith('win'):
assert(ret != 0)
else:
assert(ret == 0)
Run Code Online (Sandbox Code Playgroud)
two.py:
from shared import MMAP_SIZE,MMAP_NAME
def read_from_mmap():
map_file = mmap.mmap(-1,MMAP_SIZE,tagname=MMAP_NAME,access=mmap.ACCESS_READ)
map_file.seek(0)
data = map_file.readline().rstrip('\n')
map_file.close()
print data
Run Code Online (Sandbox Code Playgroud)
*此代码是为Windows编写的,Linux可能需要一些调整
更多信息-https: //docs.python.org/2/library/mmap.html
Redis以下方式共享动态变量:script_one.py
from redis import Redis
from time import sleep
cli = Redis('localhost')
shared_var = 1
while True:
cli.set('share_place', shared_var)
shared_var += 1
sleep(1)
Run Code Online (Sandbox Code Playgroud)
在终端(一个进程)中运行script_one:
$ python script_one.py
Run Code Online (Sandbox Code Playgroud)
script_two.py
from redis import Redis
from time import sleep
cli = Redis('localhost')
while True:
print(int(cli.get('share_place')))
sleep(1)
Run Code Online (Sandbox Code Playgroud)
在另一个终端(另一个进程)中运行script_two:
$ python script_two.py
Run Code Online (Sandbox Code Playgroud)
出去:
1
2
3
4
5
...
Run Code Online (Sandbox Code Playgroud)
依赖项:
$ pip install redis
$ apt-get install redis-server
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
42598 次 |
| 最近记录: |