Persisting state of process post mortem Python - python

Let's say I have the code:
if __name__ == "__main__":
j = 0
while True:
j = j + 1
print j
time.sleep(1)
if I Ctrl+C or if I closed the program window in the middle of runtime, is there any way to persist the state of the process before it died? And then recover the process from the exact point that it died? If not in python is there any other language that has this functionality?

Crtl+C raises KeyboardInterrupt. You can put your code inside a try except block and handle the KeyboardInterrupt before exiting.
import sys
import time
if __name__ == "__main__":
j = 0
try:
while True:
j = j + 1
print(j)
time.sleep(1)
except KeyboardInterrupt:
with open('myprog.dat', 'r') as f:
f.write('j = {}'.format(j))
sys.exit("Data saved!")
You could also check if the data file exists, and read from the data file to initialize the value of j.

Related

Parallel multiprocessing in python easy example

I need to say that multiprocessing is something new to me. I read some about it but it makes me more confused. I want to understand it on a simple example. Let's assume that we have 2 functions in first one I just increment 'a' variable and then assign it to 'number' variable, in second I start first function and each every one second I want to print 'number' variable. It should looks like:
global number
def what_number():
a=1
while True:
a+=1
number=a
def read_number():
while True:
--> #here I need to start 'what_number' function <--
time.sleep(1)
print(number)
if __name__ == "__main__":
read_number()
How can I do that? Is there an easy and proper way to do that ?
UPDATE:
I saw noxdafox answer I'm really thankfull but it isn't exactly what I want. First of all I don't want send value in first function ('main' in noxdafox code). Second I don't want to get all values so quene will won't work. I need to get after each second number of while loops. Code should be something like :
import multiprocessing
import time
number = 0
def child_process():
global number
while True:
number += 1
print(number)
def main():
process = multiprocessing.Process(target=child_process)
process.start()
while True:
print("should get same number:",number)
time.sleep(0.001)
if __name__ == "__main__":
main()
If u run above code you get something like:
but this blue selected values should be same ! and that's the main problem :)
P.S sorry for chaos
Ok it takes some time but I figured it out. All it was about Sharing state between processes now all it works like charm. Code :
from multiprocessing import Process, Value
import time
def child_process(number):
number.value = 0
while True:
number.value += 1
#print(number)
def main():
num = Value('i')
process = Process(target=child_process, args=(num,))
process.start()
while True:
print("should get same number:", num.value)
time.sleep(1)
if __name__ == "__main__":
main()
As processes live in separate memory address spaces, you cannot share variables. Moreover, you are using global variables incorrectly. Here you can see an example on how to use global variables.
The most straightforward way to share information between processes is via a Pipe or Queue.
import multiprocessing
def child_process(queue):
while True:
number = queue.get()
number += 1
queue.put(number)
def main():
number = 0
queue = multiprocessing.Queue()
process = multiprocessing.Process(target=child_process, args=[queue])
process.start()
while True:
print("Sending %d" % number)
queue.put(number)
number = queue.get()
print("Received %d" % number)
time.sleep(1)
if __name__ == "__main__":
main()

Python Multiprocessing - Use Array(), Lock() and Pool()

I've been struggling with this program for some time.
I wrote this program to learn how to run the same program in different CPU's at the same time and to reduce processing time.
By itself, the program is not complex, just detect if there are some screenshots in different directories, but as I said before my final goal is not to detect those files, but to learn multiprocessing.
To be easier to test, instead of reading files or reading user inputs, I just set those variables so you won't have to be typing those things. I'll be faster to test this way.
Here's the code:
from multiprocessing import Array, Lock, Pool
def DetectSCREENSHOT(file, counter, total):
# To check if this function is ever accessed
print 'Entered in DetectSCREENSHOT function'
if file.startswith('Screenshot') == False:
print ' (%s %%) ERROR: the image is not a screenshot ' %(round((float(counter)/total)*100, 1))
return 0
else:
print ' (%s %%) SUCCESS: the image is a screenshot' %(round((float(counter)/total)*100, 1))
return 1
def DetectPNG(file_list, counter_success_errors, lock):
# To check if this function is ever accessed
print 'Entered in DetectPNG function'
for i in range(len(file_list)):
file = file_list[i]
# If the file is an .png image:
if file.endswith('.png'):
lock.acquire()
counter_success_errors[0] = counter_success_errors[0] + 1
lock.release()
if DetectSCREENSHOT(file, counter_success_errors[0], len(file_list)) == 1:
lock.acquire()
counter_success_errors[1] = counter_success_errors[1] + 1
lock.release()
else:
lock.acquire()
counter_success_errors[2] = counter_success_errors[2] + 1
lock.release()
def Main():
# file_list = # List of lists of files in different directories
file_list = [['A.png', 'B.png', 'C.txt', 'Screenshot_1.png'], ['D.txt', 'Screenshot_2.png', 'F.png', 'Screenshot_3.png']]
# Array where the first cell is a counter, the second one, the number of successes and the third one, the number of errors.
counter_success_errors = Array('i', 3)
lock = Lock()
counter_success_errors[0] = 0
counter_success_errors[1] = 0
counter_success_errors[2] = 0
# Number of CPUS's to be used (will set the number of different processes to be run)
# CPUs = raw_input('Number of CPUs >> ')
CPUs = 2
pool = Pool(processes=CPUs)
for i in range(CPUs):
pool.apply_async(DetectPNG, [file_list[i], counter_success_errors, lock])
pool.close()
pool.join()
success = int(counter_success_errors[1])
errors = int(counter_success_errors[2])
print(' %s %s %s successfully. %s %s.' %('Detected', success, 'screenshot' if success == 1 else 'screenshots', errors, 'error' if errors == 1 else 'errors'))
#################################################
if __name__ == "__main__":
Main()
When I execute it, I don't get any errors, but it looks like it doesn't even access to both DetectPNG and DetectSCREENSHOT functions.
What's broken in the code?
Output: Detected 0 screenshots successfully. 0 errors.

Progress dots with a Thread in Python

I am trying to create a thread in Python that will poll some server as long as it won't get proper answer (HTTP GET). In order to provide convenient text UI I want to print progress dots. Another dot with every connection attempt until it finish (or just another dot with every another second of waiting).
I have found something like this: http://code.activestate.com/recipes/535141-console-progress-dots-using-threads-and-a-context-/
In this example we have context manager:
with Ticker("A test"):
time.sleep(10)
I am not sure if I understand that properly. I would like to do something like:
with Ticker("A test: "):
result = -1
while result != 0:
result = poll_server()
print "Finished."
But this does not work. Any ideas?
Cheers
Python buffers your output, so many dots will appear at once. One way around that is to import sys and use that: whenever you want to print a dot, say:
sys.stdout.write(".")
sys.stdout.flush()
The flush makes the dot appear immediately.
#! /usr/bin/python3
import sys
import time
def progress(message):
i = 0
while True:
dots = ""
i = (i % 3) + 1
dots += "." * i + " " * (3 - i)
sys.stdout.write("\r{}".format(message + dots))
sys.stdout.flush()
i += 1
time.sleep(0.3)
if __name__ == "__main__":
progress("Waiting")
More useful example:
#! /usr/bin/python3
import sys
import time
def progress_gen(message):
i = 0
while True:
for x in range(0, 4):
dots = "." * x
sys.stdout.write("{}\r".format(message + dots))
i += 1
time.sleep(0.5)
sys.stdout.write("\033[K")
yield
if __name__ == "__main__":
p = progress_gen("Waiting")
for x in range(1, 100):
next(p)
if x == 3:
break
print("Finished")
You can test it online: https://repl.it/#binbrayer/DotsProgress

Pause and resume a running script in Python 3.42 in Windows

I'm new to Python and have been googling for a couple of days and read all I can find on this forum. Might be that I don't understand it all but I haven't found a solution to my problem yet. Ask for forgiveness already if there's an answer already to my problem, then I haven't understood it.
I want to make a Pause function for my program Tennismatch. The program will when it's being run print the score of a tennis match like this: "15-0, 15-15 etc ongoing till the match ends. It will print the score line by line.
I want the user to be able to pause after x number of balls, games, etc. So I don't know when the user wants to pause and after the user has paused I want the user to be able to resume the tennismatch where it was.
Have seen the time.sleep() but as I have understood it you must know when you want to pause to use this and it also ain't an indefinetie pause like I want. With input() it's the same.
Am going to make a GUI later on when the code is finished. Happy for anything that leads me to solving my problem.
I use Windows and Python 3.42 and run the program in Shell.
A piece of the code (haven't written it all yet, it's more of a general situation when something is being printed line after line for some time and want to be able do pause in the CIL:
#self.__points = [0,0]
def playGame(self):
if self.server == True: #self.server is either True or False when someone calls playGame()
server = self.player_1.get_win_serve() #self.player_1 = an object of a class Player():
else:
server = self.player_2.get_win_serve() #get_win_serve() method returns the probability to win his serv (1-0)
while (0 < self.__points[0] - self.__points[1] >= 2 or 0 < self.__points[1] - self.__points[0] >= 2) and (self.__points[1] >= 4 or self.__points[0] >= 4):
x = random.uniform(0,1)
if x > 0 and x < server:
self.__points[0] += 1
else:
self.__points[1] += 1
# print('The score, by calling a score() function that I haven't written yet')
For dealing with events in main loop you need to make a separated thread which capture input or any other event.
import sys
from sys import stdin
from time import sleep
from threading import Thread
from Queue import Queue, Empty
def do_something():
sleep(1)
print 42
def enqueue_output(queue):
while True:
# reading line from stdin and pushing to shared queue
input = stdin.readline()
print "got input ", input
queue.put(input)
queue = Queue()
t = Thread(target=enqueue_output, args=(queue,))
t.daemon = True
t.start()
pause = False
try:
while True:
try:
command = queue.get_nowait().strip()
print 'got from queue ', command
except Empty:
print "queue is empty"
command = None
if command:
if command == 'p':
pause = True
if command == 'u':
pause = False
if not pause:
print pause
do_something()
except KeyboardInterrupt:
sys.exit(0)
I came up with the following.
while True:
try:
## Keep doing something here
## your regular code
print '.',
except KeyboardInterrupt:
## write or call pause function which could be time.sleep()
print '\nPausing... (Hit ENTER to continue, type quit to exit.)'
try:
response = raw_input()
if response.lower() == 'quit':
break
print 'Quitting...'
except KeyboardInterrupt:
print 'Resuming...'
continue
The Event loop might as well be the code I wrote with.
I don't see any user input so I assume that x emulates it. To pause the game if x < 0.1 and to unpause(/resume) it if x > 0.9, you could:
while your_condition(self.__points):
x = random.random()
if x < 0.1: # pause
self.pause()
elif x > 0.9: # resume
self.resume()
if self.is_paused:
continue # do nothing else only wait for input (`x`)
# assume your_condition() has no side-effects
# here's what the resumed version does:
print("...")
# change self.__points, etc
where pause(), resume(), is_paused() methods could be implemented as:
def __init__(self):
self.is_paused = False
def pause(self):
self.is_paused = True
def resume(self):
self.is_paused = False
as you can see the implementation is very simple.

How to get rid of frame 'blinking' effect with standard libs?

I am currently playing with some cmd/prompt animations/graphics:
import os
import time
def printFrame(timeout, count):
os.system('cls')
l=0
while True:
for k in range(0,9):
for i in range(0,9):
for j in range(0,9):
if j == k and i != 4:
print("|", end="", flush=True)
elif j !=k and i == 4:
print("-", end="", flush=True)
elif j ==k and i == 4:
print("+", end="", flush=True)
else:
print("O", end="", flush=True)
print("")
time.sleep(timeout)
os.system('cls')
l += 1
if l > count:
break
if __name__ == "__main__":
printFrame(0.08, 2)
and i want to get rid of frame blinking - especialy visible in first line, my idea was to use second printing thread:
def printFrame(timeout, count):
#print from example1
def printFrameTwo(timeout, count):
#print from example1 without os.system('cls')
if __name__ == "__main__":
p1 = threading.Thread(target = printFrame, args = (0.08, 2))
p2 = threading.Thread(target = printFrameTwo, args = (0.08, 2))
p1.start()
p2.start()
but the effect was rather disappointing - problems with synchronization and first line still very blinky, second idea was to use 'predefined frames' - but its not very educating - the bonus here is that I can print whole line at once, but still effect is not as expected, third (most promising) idea is to only change necessary 'pixels'/chars in frame - but here I need to move in frame between lines! and curses is not working on windows (at least not in standard). Do you maybe have some ideas how to bite it? (windows, standard libraries) maybe how to speed up 'os.system('cls')'?
I figured it out... You can use ANSI codes to move the cursor then clear the lines without any BLINK!
print('\033[4A\033[2K', end='')
\033[4A Moves the cursor 4 lines up (\033[{lines}A you can replace lines with however many you need) \033[2K Clears all those lines without the screen blinking. You can use it in a simple typewrite function that needs a constant message or a box around it like this:
from time import sleep
def typewrite(text: str):
lines = text.split('\n')
for line in lines:
display = ''
for char in line:
display += char
print(f'╭─ SOME MESSAGE OR SOMEONES NAME ────────────────────────────────────────────╮')
print(f'│ {display:74} │') # :74 is the same as ' ' * 74
print(f'╰────────────────────────────────────────────────────────────────────────────╯')
sleep(0.05)
print('\033[3A\033[2K', end='')
The only problem with this is that the top line is blinking. To fix this all we need to do is to add a empty line that is blinking so the user cant see it. We also move the cursor up from 3 to 4 lines.
def typewrite(text: str):
lines = text.split('\n')
for line in lines:
display = ''
for char in line:
display += char
print('')
print(f'╭─ SOME MESSAGE OR SOMEONES NAME ────────────────────────────────────────────╮')
print(f'│ {display:74} │') # :74 is the same as ' ' * 74
print(f'╰────────────────────────────────────────────────────────────────────────────╯')
sleep(0.05)
print('\033[4A\033[2K', end='')
To make this into your code just print your text and add a print('') at the start. Then use this print('\033[4A\033[2K', end='') but change the 4 to however many lines that you printed including the print(''). Then it should work without blinking. You can put print('\033[4B', end='') at the end which just moves the cursor back up.
If you want to hide the cursor you can use this gibberish or make the cursor the same color as the background:
import ctypes
if os.name == 'nt':
class _CursorInfo(ctypes.Structure):
_fields_ = [("size", ctypes.c_int),
("visible", ctypes.c_byte)]
def hide_cursor() -> None:
if os.name == 'nt':
ci = _CursorInfo()
handle = ctypes.windll.kernel32.GetStdHandle(-11)
ctypes.windll.kernel32.GetConsoleCursorInfo(handle, ctypes.byref(ci))
ci.visible = False
ctypes.windll.kernel32.SetConsoleCursorInfo(handle, ctypes.byref(ci))
def show_cursor() -> None:
if os.name == 'nt':
ci = _CursorInfo()
handle = ctypes.windll.kernel32.GetStdHandle(-11)
ctypes.windll.kernel32.GetConsoleCursorInfo(handle, ctypes.byref(ci))
ci.visible = True
ctypes.windll.kernel32.SetConsoleCursorInfo(handle, ctypes.byref(ci))
Note: All of this is still new to me so I am still testing this out to fully understand it.

Categories