Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/interfaces/psage.py
4048 views
1
r"""
2
Parallel Interface to the Sage interpreter
3
4
This is an expect interface to \emph{multiple} copy of the \sage
5
interpreter, which can all run simultaneous calculations. A PSage
6
object does not work as well as the usual Sage object, but does have
7
the great property that when you construct an object in a PSage you
8
get back a prompt immediately. All objects constructed for that
9
PSage print <<currently executing code>> until code execution
10
completes, when they print as normal.
11
12
\note{BUG -- currently non-idle PSage subprocesses do not stop when
13
\sage exits. I would very much like to fix this but don't know how.}
14
15
EXAMPLES:
16
17
We illustrate how to factor 3 integers in parallel.
18
First start up 3 parallel Sage interfaces::
19
20
sage: v = [PSage() for _ in range(3)]
21
22
Next, request factorization of one random integer in each copy. ::
23
24
sage: w = [x('factor(2^%s-1)'% randint(250,310)) for x in v] # long time (5s on sage.math, 2011)
25
26
Print the status::
27
28
sage: w # long time, random output (depends on timing)
29
[3 * 11 * 31^2 * 311 * 11161 * 11471 * 73471 * 715827883 * 2147483647 * 4649919401 * 18158209813151 * 5947603221397891 * 29126056043168521,
30
<<currently executing code>>,
31
9623 * 68492481833 * 23579543011798993222850893929565870383844167873851502677311057483194673]
32
33
Note that at the point when we printed two of the factorizations had
34
finished but a third one hadn't. A few seconds later all three have
35
finished::
36
37
sage: w # long time, random output
38
[3 * 11 * 31^2 * 311 * 11161 * 11471 * 73471 * 715827883 * 2147483647 * 4649919401 * 18158209813151 * 5947603221397891 * 29126056043168521,
39
23^2 * 47 * 89 * 178481 * 4103188409 * 199957736328435366769577 * 44667711762797798403039426178361,
40
9623 * 68492481833 * 23579543011798993222850893929565870383844167873851502677311057483194673]
41
"""
42
43
import os, time
44
45
from sage0 import Sage, SageElement
46
47
48
number = 0
49
50
51
class PSage(Sage):
52
def __init__(self, **kwds):
53
if kwds.has_key('server'):
54
raise NotImplementedError, "PSage doesn't work on remote server yet."
55
Sage.__init__(self, **kwds)
56
import sage.misc.misc
57
T = sage.misc.misc.tmp_dir('sage_smp')
58
self.__tmp_dir = T
59
self.__tmp = '%s/lock'%T
60
self._unlock()
61
self._unlock_code = "open('%s','w').write('__unlocked__')"%self.__tmp
62
63
global number
64
self._number = number
65
number += 1
66
67
def __repr__(self):
68
return 'A running non-blocking (parallel) instance of Sage (number %s)'%(self._number)
69
70
def _unlock(self):
71
self._locked = False
72
open(self.__tmp, 'w').write('__unlocked__')
73
74
def _lock(self):
75
self._locked = True
76
open(self.__tmp, 'w').write('__locked__')
77
78
def _start(self):
79
Sage._start(self)
80
self.expect().timeout = 0.25
81
self.expect().delaybeforesend = 0.01
82
83
def is_locked(self):
84
if open(self.__tmp).read() == '__locked__':
85
try:
86
self.expect().expect(self._prompt)
87
self.expect().expect(self._prompt)
88
except:
89
pass
90
return open(self.__tmp).read() == '__locked__'
91
92
def __del__(self):
93
print "deleting"
94
for x in os.listdir(self.__tmp_dir):
95
os.remove('%s/%s'%(self.__tmp_dir, x))
96
os.removedirs(self.__tmp_dir)
97
if not (self._expect is None):
98
cmd = 'kill -9 %s'%self._expect.pid
99
print cmd
100
os.system(cmd)
101
Sage.__del__(self)
102
103
def eval(self, x, strip=True, **kwds):
104
"""
105
x -- code
106
strip --ignored
107
"""
108
if self.is_locked():
109
return "<<currently executing code>>"
110
if self._locked:
111
self._locked = False
112
#self._expect.expect('__unlocked__')
113
self.expect().send('\n')
114
self.expect().expect(self._prompt)
115
self.expect().expect(self._prompt)
116
try:
117
return Sage.eval(self, x, **kwds)
118
except:
119
return "<<currently executing code>>"
120
121
122
def get(self, var):
123
"""
124
Get the value of the variable var.
125
"""
126
try:
127
return self.eval('print %s'%var)
128
except:
129
return "<<currently executing code>>"
130
131
def set(self, var, value):
132
"""
133
Set the variable var to the given value.
134
"""
135
cmd = '%s=%s'%(var,value)
136
self._send_nowait(cmd)
137
time.sleep(0.02)
138
139
def _send_nowait(self, x):
140
if x.find('\n') != -1:
141
raise ValueError, "x must not have any newlines"
142
# Now we want the client Python process to execute two things.
143
# The first is x and the second is c. The effect of c
144
# will be to unlock the lock.
145
if self.is_locked():
146
return "<<currently executing code>>"
147
E = self.expect()
148
self._lock()
149
E.write(self.preparse(x) + '\n')
150
try:
151
E.expect(self._prompt)
152
except:
153
pass
154
E.write(self._unlock_code + '\n\n')
155
156
def _object_class(self):
157
return PSageElement
158
159
class PSageElement(SageElement):
160
def is_locked(self):
161
return self.parent().is_locked()
162
163