Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Feb 13, 2025. It is now read-only.
forked frompython/cpython
Anselm Kruis edited this pageJan 1, 2016 ·1 revision

Pickling

One of the main features ofStackless is its ability topickle and unpickletasklets. That means that a runningprogram inside a tasklet can be persistently stored to afile or string. Later, it can be restored again and cancontinue to run at the point where it was previouslyhalted. This need not be on the same machine!

Example -Pickling and unpickling simple tasklets:

fromstacklessimportrun,schedule,taskletimportpickledefaCallable(name):print"  aCallable<%s>: Before schedule()"%nameschedule()print"  aCallable<%s>: After schedule()"%nametasks= []fornamein"ABCDE":tasks.append(tasklet(aCallable)(name))print"Schedule 1:"schedule()printprint"Pickling..."pickledTasks=pickle.dumps(tasks)printprint"Schedule 2:"schedule()unpickledTasks=pickle.loads(pickledTasks)fortaskinunpickledTasks:task.insert()printprint"Schedule Unpickled Tasks:"schedule()

Custom Tasklet or Channel Subclasses

Subclassing thetasklet orchannel classes ispretty straightforward. In fact, if you need to persistany extra information with your tasklets or channels,you will need to do this. Neither of the classes havetheirslots or instance dictionary persisted with themwhen pickled.

The following example should illustrate exactly whatthe problem is.

Example -Named tasklets:

classCustomTasklet(stackless.tasklet):name="UNNAMED"def__str__(self):return"<CustomTasklet(name='%s')>"%self.namedeff():passt1=CustomTasklet(f)()t1.name="Pointless"s=pickle.dumps(t1)t2=pickle.loads(s)

Output:

>>>print t2.name== t1.nameFalse>>>print t2.name'UNNAMED'

However, you can easily get around this by overriding__reduce__() /__reduce_ex__() and__setstate__()to add whatever else you want to be persisted.

Example -Named tasklets that persist their name:

classCustomTasklet(stackless.tasklet):name="UNNAMED"def__str__(self):return"<CustomTasklet(name='%s')>"%self.name# When this is present, it is called in lieu of __reduce__.# As the base tasklet class provides it, we need to as well.def__reduce_ex__(self,pickleVersion):returnself.__reduce__()def__reduce__(self):# Get into the list that will eventually be returned to# __setstate__ and append our own entry into it (the# dictionary of instance variables).ret=list(stackless.tasklet.__reduce__(self))l=list(ret[2])l.append(self.__dict__)ret[2]=tuple(l)returntuple(ret)def__setstate__(self,l):# Update the instance dictionary with the value we added in.self.__dict__.update(l[-1])# Let the tasklet get on with being reconstituted by giving# it the original list (removing our addition).returnstackless.tasklet.__setstate__(self,l[:-1])deff():passt1=CustomTasklet(f)()t1.name="Pointless"s=pickle.dumps(t1)t2=pickle.loads(s)

Output:

>>>print t2.name== t1.nameTrue>>>print t2.name'Pointless'

Tasklets

Pickling a tasklet that is blocked on a channel, willnot result in the pickling of that channel unless youare explicitly pickling a reference to that channelalong with it.

If a tasklet is blocked on a channel that is not inany scope contained in the function the tasklet isbound to, then it will not be pickled.

Example -Channel not pickled:

deff():c.receive()c=stackless.channel()t1=stackless.tasklet(f)()s=pickle.dumps(t1)t2=pickle.loads(s)# The tasklet will not be attached to a channel.assertt2._channelisNone

Example -Channel pickled:

deff(c):c.receive()c=stackless.channel()t1=stackless.tasklet(f)(c)s=pickle.dumps(t1)t2=pickle.loads(s)# The tasklet will be attached to a channel.assertt2._channelisnotNone

Channels

Pickling a channel, will also pickle any taskletscurrently blocked on it. But sometimes you just want topickle the channel with only some of those tasklets stillblocked on it, or perhaps, tasklets you isolate from thechannel on their own. You can do this by using__reduce__() and__setstate__().

Example -Removing a tasklet from a channel andpickling the results:

# Given a channel 'c' with four tasklets blocked on it, where# we want to just pickle the first.# Get the channel state.x,y, (balance,flags,tasklets)=c.__reduce__()# Get the tasklet and remove it from the ones on the channel.t=tasklets[0]deltasklets[0]# Rebuild the channel without the tasklet.  You do not need to# bother adjusting the balance for the changes you made to the# list of blocked tasklets, as it is recalculated automatically.# This will replace the channels existing state.  But if you# want to keep the channel as it is, you can create a new# and use it in place of 'c'.c.__setstate__((balance,flags,tasklets))# Pickle just the tasklet (and whatever it holds a reference to).s1=pickle.dumps(t)# Pickle the channel which no longer has that channel.s2=pickle.dumps(c)

Two important things to know about the values you getfrom__reduce__() and pass to__setstate__():

  • The list of tasklets, featured in both functions, is in theorder in which the tasklets came to be blocked on the channel.
  • When passed to__setstate__() the actual balance value isnot used, except for its sign, which is used to indicate whetherthe blocked tasklets are receiving or sending.

Clone this wiki locally


[8]ページ先頭

©2009-2025 Movatter.jp