Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
C
cpython
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
cpython
Commits
f4e13a45
Kaydet (Commit)
f4e13a45
authored
Kas 08, 2000
tarafından
Guido van Rossum
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Add 1994 Coroutine module by Tim Peters
üst
704925c7
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
332 additions
and
0 deletions
+332
-0
Coroutine.py
Demo/threads/Coroutine.py
+160
-0
README
Demo/threads/README
+4
-0
fcmp.py
Demo/threads/fcmp.py
+64
-0
squasher.py
Demo/threads/squasher.py
+104
-0
No files found.
Demo/threads/Coroutine.py
0 → 100644
Dosyayı görüntüle @
f4e13a45
# Coroutine implementation using Python threads.
#
# Combines ideas from Guido's Generator module, and from the coroutine
# features of Icon and Simula 67.
#
# To run a collection of functions as coroutines, you need to create
# a Coroutine object to control them:
# co = Coroutine()
# and then 'create' a subsidiary object for each function in the
# collection:
# cof1 = co.create(f1 [, arg1, arg2, ...]) # [] means optional,
# cof2 = co.create(f2 [, arg1, arg2, ...]) #... not list
# cof3 = co.create(f3 [, arg1, arg2, ...])
# etc. The functions need not be distinct; 'create'ing the same
# function multiple times gives you independent instances of the
# function.
#
# To start the coroutines running, use co.tran on one of the create'd
# functions; e.g., co.tran(cof2). The routine that first executes
# co.tran is called the "main coroutine". It's special in several
# respects: it existed before you created the Coroutine object; if any of
# the create'd coroutines exits (does a return, or suffers an unhandled
# exception), EarlyExit error is raised in the main coroutine; and the
# co.detach() method transfers control directly to the main coroutine
# (you can't use co.tran() for this because the main coroutine doesn't
# have a name ...).
#
# Coroutine objects support these methods:
#
# handle = .create(func [, arg1, arg2, ...])
# Creates a coroutine for an invocation of func(arg1, arg2, ...),
# and returns a handle ("name") for the coroutine so created. The
# handle can be used as the target in a subsequent .tran().
#
# .tran(target, data=None)
# Transfer control to the create'd coroutine "target", optionally
# passing it an arbitrary piece of data. To the coroutine A that does
# the .tran, .tran acts like an ordinary function call: another
# coroutine B can .tran back to it later, and if it does A's .tran
# returns the 'data' argument passed to B's tran. E.g.,
#
# in coroutine coA in coroutine coC in coroutine coB
# x = co.tran(coC) co.tran(coB) co.tran(coA,12)
# print x # 12
#
# The data-passing feature is taken from Icon, and greatly cuts
# the need to use global variables for inter-coroutine communication.
#
# .back( data=None )
# The same as .tran(invoker, data=None), where 'invoker' is the
# coroutine that most recently .tran'ed control to the coroutine
# doing the .back. This is akin to Icon's "&source".
#
# .detach( data=None )
# The same as .tran(main, data=None), where 'main' is the
# (unnameable!) coroutine that started it all. 'main' has all the
# rights of any other coroutine: upon receiving control, it can
# .tran to an arbitrary coroutine of its choosing, go .back to
# the .detach'er, or .kill the whole thing.
#
# .kill()
# Destroy all the coroutines, and return control to the main
# coroutine. None of the create'ed coroutines can be resumed after a
# .kill(). An EarlyExit exception does a .kill() automatically. It's
# a good idea to .kill() coroutines you're done with, since the
# current implementation consumes a thread for each coroutine that
# may be resumed.
import
thread
import
sync
class
_CoEvent
:
def
__init__
(
self
,
func
):
self
.
f
=
func
self
.
e
=
sync
.
event
()
def
__repr__
(
self
):
if
self
.
f
is
None
:
return
'main coroutine'
else
:
return
'coroutine for func '
+
self
.
f
.
func_name
def
__hash__
(
self
):
return
id
(
self
)
def
__cmp__
(
x
,
y
):
return
cmp
(
id
(
x
),
id
(
y
))
def
resume
(
self
):
self
.
e
.
post
()
def
wait
(
self
):
self
.
e
.
wait
()
self
.
e
.
clear
()
Killed
=
'Coroutine.Killed'
EarlyExit
=
'Coroutine.EarlyExit'
class
Coroutine
:
def
__init__
(
self
):
self
.
active
=
self
.
main
=
_CoEvent
(
None
)
self
.
invokedby
=
{
self
.
main
:
None
}
self
.
killed
=
0
self
.
value
=
None
self
.
terminated_by
=
None
def
create
(
self
,
func
,
*
args
):
me
=
_CoEvent
(
func
)
self
.
invokedby
[
me
]
=
None
thread
.
start_new_thread
(
self
.
_start
,
(
me
,)
+
args
)
return
me
def
_start
(
self
,
me
,
*
args
):
me
.
wait
()
if
not
self
.
killed
:
try
:
try
:
apply
(
me
.
f
,
args
)
except
Killed
:
pass
finally
:
if
not
self
.
killed
:
self
.
terminated_by
=
me
self
.
kill
()
def
kill
(
self
):
if
self
.
killed
:
raise
TypeError
,
'kill() called on dead coroutines'
self
.
killed
=
1
for
coroutine
in
self
.
invokedby
.
keys
():
coroutine
.
resume
()
def
back
(
self
,
data
=
None
):
return
self
.
tran
(
self
.
invokedby
[
self
.
active
],
data
)
def
detach
(
self
,
data
=
None
):
return
self
.
tran
(
self
.
main
,
data
)
def
tran
(
self
,
target
,
data
=
None
):
if
not
self
.
invokedby
.
has_key
(
target
):
raise
TypeError
,
'.tran target '
+
`target`
+
\
' is not an active coroutine'
if
self
.
killed
:
raise
TypeError
,
'.tran target '
+
`target`
+
' is killed'
self
.
value
=
data
me
=
self
.
active
self
.
invokedby
[
target
]
=
me
self
.
active
=
target
target
.
resume
()
me
.
wait
()
if
self
.
killed
:
if
self
.
main
is
not
me
:
raise
Killed
if
self
.
terminated_by
is
not
None
:
raise
EarlyExit
,
`self.terminated_by`
+
' terminated early'
return
self
.
value
# end of module
Demo/threads/README
Dosyayı görüntüle @
f4e13a45
...
...
@@ -8,3 +8,7 @@ find.py Parallelized "find(1)" (looks for directories).
sync.py Condition variables primitives by Tim Peters.
telnet.py Version of ../sockets/telnet.py using threads.
wpi.py Version of ../scripts/pi.py using threads (needs stdwin).
Coroutine.py Coroutines using threads, by Tim Peters (22 May 94)
fcmp.py Example of above, by Tim
squasher.py Another example of above, also by Tim
Demo/threads/fcmp.py
0 → 100644
Dosyayı görüntüle @
f4e13a45
# Coroutine example: controlling multiple instances of a single function
from
Coroutine
import
*
# fringe visits a nested list in inorder, and detaches for each non-list
# element; raises EarlyExit after the list is exhausted
def
fringe
(
co
,
list
):
for
x
in
list
:
if
type
(
x
)
is
type
([]):
fringe
(
co
,
x
)
else
:
co
.
detach
(
x
)
def
printinorder
(
list
):
co
=
Coroutine
()
f
=
co
.
create
(
fringe
,
co
,
list
)
try
:
while
1
:
print
co
.
tran
(
f
),
except
EarlyExit
:
pass
print
printinorder
([
1
,
2
,
3
])
# 1 2 3
printinorder
([[[[
1
,[
2
]]],
3
]])
# ditto
x
=
[
0
,
1
,
[
2
,
[
3
]],
[
4
,
5
],
[[[
6
]]]
]
printinorder
(
x
)
# 0 1 2 3 4 5 6
# fcmp lexicographically compares the fringes of two nested lists
def
fcmp
(
l1
,
l2
):
co1
=
Coroutine
();
f1
=
co1
.
create
(
fringe
,
co1
,
l1
)
co2
=
Coroutine
();
f2
=
co2
.
create
(
fringe
,
co2
,
l2
)
while
1
:
try
:
v1
=
co1
.
tran
(
f1
)
except
EarlyExit
:
try
:
v2
=
co2
.
tran
(
f2
)
except
EarlyExit
:
return
0
co2
.
kill
()
return
-
1
try
:
v2
=
co2
.
tran
(
f2
)
except
EarlyExit
:
co1
.
kill
()
return
1
if
v1
!=
v2
:
co1
.
kill
();
co2
.
kill
()
return
cmp
(
v1
,
v2
)
print
fcmp
(
range
(
7
),
x
)
# 0; fringes are equal
print
fcmp
(
range
(
6
),
x
)
# -1; 1st list ends early
print
fcmp
(
x
,
range
(
6
))
# 1; 2nd list ends early
print
fcmp
(
range
(
8
),
x
)
# 1; 2nd list ends early
print
fcmp
(
x
,
range
(
8
))
# -1; 1st list ends early
print
fcmp
([
1
,[[
2
],
8
]],
[[[
1
],
2
],
8
])
# 0
print
fcmp
([
1
,[[
3
],
8
]],
[[[
1
],
2
],
8
])
# 1
print
fcmp
([
1
,[[
2
],
8
]],
[[[
1
],
2
],
9
])
# -1
# end of example
Demo/threads/squasher.py
0 → 100644
Dosyayı görüntüle @
f4e13a45
# Coroutine example: general coroutine transfers
#
# The program is a variation of a Simula 67 program due to Dahl & Hoare,
# who in turn credit the original example to Conway.
#
# We have a number of input lines, terminated by a 0 byte. The problem
# is to squash them together into output lines containing 72 characters
# each. A semicolon must be added between input lines. Runs of blanks
# and tabs in input lines must be squashed into single blanks.
# Occurrences of "**" in input lines must be replaced by "^".
#
# Here's a test case:
test
=
"""
\
d = sqrt(b**2 - 4*a*c)
twoa = 2*a
L = -b/twoa
R = d/twoa
A1 = L + R
A2 = L - R
\0
"""
# The program should print:
# d = sqrt(b^2 - 4*a*c);twoa = 2*a; L = -b/twoa; R = d/twoa; A1 = L + R;
#A2 = L - R
#done
# getline: delivers the next input line to its invoker
# disassembler: grabs input lines from getline, and delivers them one
# character at a time to squasher, also inserting a semicolon into
# the stream between lines
# squasher: grabs characters from disassembler and passes them on to
# assembler, first replacing "**" with "^" and squashing runs of
# whitespace
# assembler: grabs characters from squasher and packs them into lines
# with 72 character each, delivering each such line to putline;
# when it sees a null byte, passes the last line to putline and
# then kills all the coroutines
# putline: grabs lines from assembler, and just prints them
from
Coroutine
import
*
def
getline
(
text
):
for
line
in
string
.
splitfields
(
text
,
'
\n
'
):
co
.
back
(
line
)
def
disassembler
():
while
1
:
card
=
co
.
tran
(
cogetline
)
for
i
in
range
(
len
(
card
)):
co
.
tran
(
cosquasher
,
card
[
i
])
co
.
tran
(
cosquasher
,
';'
)
def
squasher
():
while
1
:
ch
=
co
.
tran
(
codisassembler
)
if
ch
==
'*'
:
ch2
=
co
.
tran
(
codisassembler
)
if
ch2
==
'*'
:
ch
=
'^'
else
:
co
.
tran
(
coassembler
,
ch
)
ch
=
ch2
if
ch
in
'
\t
'
:
while
1
:
ch2
=
co
.
tran
(
codisassembler
)
if
ch2
not
in
'
\t
'
:
break
co
.
tran
(
coassembler
,
' '
)
ch
=
ch2
co
.
tran
(
coassembler
,
ch
)
def
assembler
():
line
=
''
while
1
:
ch
=
co
.
tran
(
cosquasher
)
if
ch
==
'
\0
'
:
break
if
len
(
line
)
==
72
:
co
.
tran
(
coputline
,
line
)
line
=
''
line
=
line
+
ch
line
=
line
+
' '
*
(
72
-
len
(
line
))
co
.
tran
(
coputline
,
line
)
co
.
kill
()
def
putline
():
while
1
:
line
=
co
.
tran
(
coassembler
)
print
line
import
string
co
=
Coroutine
()
cogetline
=
co
.
create
(
getline
,
test
)
coputline
=
co
.
create
(
putline
)
coassembler
=
co
.
create
(
assembler
)
codisassembler
=
co
.
create
(
disassembler
)
cosquasher
=
co
.
create
(
squasher
)
co
.
tran
(
coputline
)
print
'done'
# end of example
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment