Using multiprocessing does not reduce time of calculation - python
A question.
Using multiprocessing is for having a faster code.
But after using the following framework, getting the outputs takes the same time or more as it took in normal code.
import multiprocessing
def code() :
my code
if __name__ == '__main__' :
p = multiprocessing.Process(target = code)
p.start()
p.join()
because of being 2 processors laptop, after running this code the program wants me to import data two times.
The problem is time which did not make any sense in this way. I run into a long time as long as the normal code without parallelism.
import numpy as np
from scipy.integrate import odeint
from math import *
from scipy.integrate import quad
import pandas as pd
import os
import warnings
warnings.filterwarnings("ignore")
#you need add the following 3 lines
from multiprocessing import Pool
from multiprocessing import Process
import multiprocessing
print("Model 4, Equation 11")
print("")
###################### STEP NUMBER #######################
N = int(input("PLEASE ENTER NUMBER OF STEP WALKS: ")) # Step walk by user
dec=int(input("NUMBER OF DECIMAL PLACES OF OUTPUTS (RECOMENDED 10-15)?"))
print("")
print("PLEASE WAIT, METROPOLIS HASTINGS IS RUNNING ... ")
print("")
def FIT():
##########################################################
od0o = np.zeros((N,))
od0o[0]=0.72
od0n = np.zeros((N,))
Mo = np.zeros((N,))
Mo[0]= 0
Mn = np.zeros((N,))
co = np.zeros((N,))
co[0]= 0.84
cn = np.zeros((N,))
bo = np.zeros((N,))
bo[0]= 0.02
bn = np.zeros((N,))
H0o = np.zeros((N,))
H0o[0]= 70
H0n = np.zeros((N,))
Orco = np.zeros((N,))
Orco[0]= 0.0003
Orcn = np.zeros((N,))
temp=1e10 # a big number
##########################################################
CovCMB=[[3.182,18.253,-1.429],
[18.253,11887.879,-193.808],
[-1.429,-193.808,4.556]] # CMB DATA
##########################################################
def OD_H(U,z,c,b,Orc):
od, H = U
Omegai = 3 * b * ((1- od - 2*(Orc)**0.5) + (1- od - 2*(Orc)**0.5)**2/(1-2*(Orc)**0.5)) #equation 10
div1=np.divide((c**2-od),(1+z),where=(1+z)!=0)
div2=np.divide(H ,(1+z),where=(1+z)!=0)
dMdt = (div1)*(6*od+6-9*(od/c**2)+ Omegai)*(1+c**2+od*(1-3/c**2))**(-1)
dHdt = (div2)*(6*od+6-9*(od/c**2)+ Omegai)*(1+c**2+od*(1-3/c**2))**(-1)
return [dMdt, dHdt]
def solution(H0,z1,z,od0,c,b,Orc):
U = odeint(OD_H,[od0,H0],[z1,z], args=(c,b,Orc))[-1]
od, H = U
return H
##########################################################
def DMCMB1(H0,z1,z,od0,c,b,Orc):
dm = 1090 * 1/solution(H0,z1,z,od0,c,b,Orc)
return dm
def R1(H0,z1,z,od0,c,b,Orc):
#r=sqrt(Om)*(70/299000)*rszstar(z,Om,Od)
r = sqrt(1-od0-2*(Orc)**0.5)*DMCMB1(H0,z1,z,od0,c,b,Orc)
return r
def lA1(H0,z1,z,od0,c,b,Orc):
la=((3.14*299000/H0)*DMCMB1(H0,z1,z,od0,c,b,Orc))/(153)
return la
def CMBMATRIX1(H0,z1,z,od0,c,b,Orc,M):
hmCMB1=[lA1(H0,z1,z,od0,c,b,Orc)-301.57, R1(H0,z1,z,od0,c,b,Orc)-1.7382+M, 0.0222-0.02262]
vmCMB1=[[lA1(H0,z1,z,od0,c,b,Orc)-301.57], [R1(H0,z1,z,od0,c,b,Orc)-1.7382], [0.0222-0.02262]]
fmCMB1=np.dot(hmCMB1,CovCMB)
smCMB1=np.dot(fmCMB1,vmCMB1)[0]
return smCMB1
######################################################
def TOTAL(H0, od0, c, b,Orc, M) :
total = CMBMATRIX1(H0,0,1090,od0,c,b,Orc,M)
return total
######################################################
################## MCMC - MH #########################
highest=0
pat='C:/Users/21/Desktop/MHT/Models/outputs'
file_path = os.path.join(pat,'Model3.txt')
file_path2 = os.path.join(pat,'Model3min.txt')
with open(file_path, 'w') as f: # DATA WILL BE SAVED IN THIS FILE, PLEASE BECAREFUL TO CHANGE THE NAME IN EACH RUN TO AVOIDE REWRITING.
with open(file_path2, 'w') as d:
for i in range (1,N):
num = 0
R = np.random.uniform(0,1)
while True:
num += 1
od0n[i] = od0o[i-1] + 0.001 * np.random.normal()
H0n[i] = H0o[i-1] + 0.01 * np.random.normal()
bn[i] = bo[i-1] + 0.001 * np.random.normal()
cn[i] = co[i-1] + 0.001 * np.random.normal()
Mn[i] = Mo[i-1] + 0.01 * np.random.normal()
Orcn[i] = Orco[i-1] + 0.00001 * np.random.normal()
L = np.exp(-0.5 * (TOTAL(H0n[i], od0n[i], cn[i], bn[i],Orcn[i], Mn[i]) - TOTAL(H0o[i-1], od0o[i-1], co[i-1], bo[i-1],Orco[i-1], Mo[i-1]))) # L = exp(-( x^2 )/2)
LL=min(1,max(L,0))
if LL>R:
od0o[i]= od0n[i]
H0o[i] = H0n[i]
bo[i] = bn[i]
co[i] = cn[i]
Mo[i] = Mn[i]
Orco[i] = Orcn[i]
chi = TOTAL(H0o[i], od0o[i], co[i], bo[i],Orco[i], Mo[i])
else:
od0o[i]= od0o[i-1]
H0o[i] = H0o[i-1]
bo[i] = bo[i-1]
co[i] = co[i-1]
Mo[i] = Mo[i-1]
Orco[i] = Orco[i-1]
chi = TOTAL(H0o[i], od0o[i], co[i], bo[i],Orco[i], Mo[i])
if (Mo[i]>0 and 0<bo[i]<0.09 and Orco[i]>0) or num>100: # constraining the value to stay in positive area
highest = max(num, highest)
break
f.write("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}\t{10}\t{11}\t{12}\n".format(round(chi,dec),' ',round(H0o[i],dec),' ',round(od0o[i],dec),' ',
round(co[i],dec),' ',round(bo[i],dec),' ',
round(Orco[i],dec),' ',round(Mo[i],dec)))
if chi<temp:
temp=chi
aa = H0o[i]
bb = od0o[i]
cc = co[i]
dd = bo[i]
ee = Mo[i]
ff=Orco[i]
Om=1-2*sqrt(Orco[i])-od0o[i]
# minimum of chi and its parameters
d.write("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}\t{10}\t{11}\t{12},\t{13}\t{14}\n".format(round(temp,dec), "H =", round(aa,dec), "Orc=",
round(ff,dec), "OD =",round(bb,dec),"c =",
round(cc,dec),"b =", round(dd,dec),
"M =",round(ee,dec),"Om =",round(Om,dec)))
print(round(temp,dec), "H =", round(aa,dec), "Orc=",round(ff,dec), "OD =",round(bb,dec),"c =", round(cc,dec),"b =", round(dd,dec), "M =",round(ee,dec),"Om =",round(Om,dec))
#print(highest)
print("")
#test = input("Press the enter to exit...")
#print(test)
if __name__ == '__main__':
p = multiprocessing.Process(target=FIT)
p.start()
p.join()
I think you missed main concept of multiprocessing. It does not run your code faster, it just let's you run something in another process to bypass GIL (https://wiki.python.org/moin/GlobalInterpreterLock).
It can be used to parallel computing of some function for different input values, like this example from docs
from multiprocessing import Pool
def f(x):
return x*x
if __name__ == '__main__':
p = Pool(5)
print(p.map(f, [1, 2, 3]))
Which results in computing f in different processes and just each of them returning separate value
You are creating only one process and all of your other logic is sequential thats why there is no change in performance because all of your code will run sequentially.
There are two different scenarios where you can use multiprocessing
Totally Independent functionalities : If you have functionalities which are totally Independent and there is no restriction to execute them sequentially you can execute them in parallel this way none of these functionalities will have to wait for each other.
A good analogy will be reading news paper and having breakfast here no need of doing them sequentially so we can do them at the same time.
Executing same functionality for different inputs :
If you are executing a functionality repeatedly for different input then you can execute multiple instances of that functionality for several inputs at a time.
For analogy think of single ticket counter
Then think of multiple ticket counters same functionality multiple instances.
Find these scenarios in your code then try to parallelize those functionalities.
Hope it helped.
Related
convergence issue encountered while implementing policy iteration from scratch
I am trying to implement policy iteration from scratch. I have a 2D grid world environment named GridWorld that returns the successor state and reward from a given action, and it also has a function that returns the transition probability. Below is my code for policy iteration: import matplotlib matplotlib.use('Agg') import random import numpy as np import matplotlib.pyplot as plt import gridworld from tqdm import tqdm class PolicyIteration: def __init__(self, env, gamma): self.env = env self.num_states = self.env.num_states self.num_actions = self.env.num_actions self.max_num_steps = self.env.max_num_steps self.gamma = gamma #discount factor self.values = np.zeros(self.num_states) #Initialize `values` as zeros self.policy = np.random.randint(0, self.num_actions, self.num_states) def one_policy_evaluation(self): """ Runs one iteration of policy evaluation and updates the value function. :return: the maximum change in value function """ delta = 0 for s in range(self.num_states): v = self.values[s] a = self.policy[s] (s_new, r, _) = self.env.step(a) p = self.env.p(s_new, s, a) """ update V(s)""" self.values[s] = np.sum(p * (r + self.gamma * self.values[s_new])) delta = max(delta, abs(v - self.values[s])) return delta def run_policy_evaluation(self, tol = 1e-3): """ Runs policy evaluation until convergence. :param tol: the tolerance level for convergence :return: the number of iterations of policy evaluation until convergence """ delta = self.one_policy_evaluation() delta_history = [delta] while delta > tol: delta = self.one_policy_evaluation() delta_history.append(delta) return len(delta_history) def run_policy_improvement(self): update_policy_count = 0 for s in range(self.num_states): temp = self.policy[s] v_list = np.zeros(self.num_actions) for a in range(self.num_actions): (s_new, r, _) = self.env.step(a) p = self.env.p(s_new, s, a) v_list[a] = np.sum(p * (r + self.gamma * self.values[s_new])) self.policy[s] = np.argmax(v_list) if temp != self.policy[s]: update_policy_count += 1 return update_policy_count def train(self, tol=1e-3, max_iters=100, plot=True): eval_count = self.run_policy_evaluation(tol) eval_count_history = [eval_count] policy_change = self.run_policy_improvement() policy_change_history = [policy_change] epoch = 0 val_history= [] for i in tqdm(range(max_iters)): epoch += 1 new_eval_count = self.run_policy_evaluation(tol) new_policy_change = self.run_policy_improvement() eval_count_history.append(new_eval_count) policy_change_history.append(new_policy_change) val_history.append(np.mean(self.values)) if new_policy_change == 0: break print(f'# epoch: {len(policy_change_history)}') print(f'eval count = {eval_count_history}') print(f'policy change = {policy_change_history}') if plot is True: plt.figure(dpi=200) plt.plot(val_history) plt.tight_layout() plt.savefig('policy_iteration.png') plt.show() def main(): env = gridworld.GridWorld(hard_version=False) agent = PolicyIteration(env, gamma=0.95) agent.train() if __name__ == '__main__': main() However, based on the figure generated, the sequence of values is oscillating up and down and never converges. I followed the algorithm in the Sutton book step by step, and can't find any issues with my code yet: Any help is greatly appreciated!
Python decimal.InvalidOperation Error Using A Large Number
In python, I wrote a program to work out the value of pi using the Chudnovsky Algorithm. It works on numbers under 800. However, if I use a number above 800, it returns a decimal.InvalidOperation error. This is my code: from math import factorial from decimal import Decimal, getcontext getcontext().prec = 1000 pi_input = input("How Many Digits Of Pi Are To Be Represented: ") num = int(pi_input) def cal(n): t = Decimal(0) pi = Decimal(0) deno = Decimal(0) for k in range(n): t = ((-1) ** k) * (factorial(6 * k)) * (13591409 + 545140134 * k) deno = factorial(3 * k) * (factorial(k) ** 3) * (640320 ** (3 * k)) pi += Decimal(t) / Decimal(deno) pi = pi * Decimal(12) / Decimal(640320 ** Decimal(1.5)) pi = 1 / pi return round(pi, n) print(cal(num)) Could Anyone Please Help Me?
I wouldn't recommend your method. Try using the gmpy module like this: import sys import math import os.path from gmpy2 import mpz, sqrt from time import time, sleep print_pi = input("Should The Value Of Pi Be Printed: ").lower() print_pi_bool = 0 if "y" in print_pi: print_pi_bool = True elif "n" in print_pi: print_pi = False else: print("Incorrect Input. Please Try Again.") sys.exit() def sqrt(n, one): """ Return the square root of n as a fixed point number with the one passed in. It uses a second order Newton-Raphson convgence. This doubles the number of significant figures on each iteration. """ # Use floating point arithmetic to make an initial guess floating_point_precision = 10**16 n_float = float((n * floating_point_precision) // one) / floating_point_precision x = (int(floating_point_precision * math.sqrt(n_float)) * one) // floating_point_precision n_one = n * one count = 0 while 1: count += 1 print(count) x_old = x x = (x + n_one // x) // 2 if x == x_old: break return x def pi_chudnovsky_bs(digits): """ Compute int(pi * 10**digits) This is done using Chudnovsky's series with binary splitting """ C = 640320 C3_OVER_24 = C**3 // 24 def bs(a, b): """ Computes the terms for binary splitting the Chudnovsky infinite series a(a) = +/- (13591409 + 545140134*a) p(a) = (6*a-5)*(2*a-1)*(6*a-1) b(a) = 1 q(a) = a*a*a*C3_OVER_24 returns P(a,b), Q(a,b) and T(a,b) """ if b - a == 1: # Directly compute P(a,a+1), Q(a,a+1) and T(a,a+1) if a == 0: Pab = Qab = mpz(1) else: Pab = mpz((6*a-5)*(2*a-1)*(6*a-1)) Qab = mpz(a*a*a*C3_OVER_24) Tab = Pab * (13591409 + 545140134*a) # a(a) * p(a) if a & 1: Tab = -Tab else: # Recursively compute P(a,b), Q(a,b) and T(a,b) # m is the midpoint of a and b m = (a + b) // 2 # Recursively calculate P(a,m), Q(a,m) and T(a,m) Pam, Qam, Tam = bs(a, m) # Recursively calculate P(m,b), Q(m,b) and T(m,b) Pmb, Qmb, Tmb = bs(m, b) # Now combine Pab = Pam * Pmb Qab = Qam * Qmb Tab = Qmb * Tam + Pam * Tmb return Pab, Qab, Tab # how many terms to compute DIGITS_PER_TERM = math.log10(C3_OVER_24/6/2/6) N = int(digits/DIGITS_PER_TERM + 1) # Calclate P(0,N) and Q(0,N) P, Q, T = bs(0, N) one_squared = mpz(10)**(2*digits) sqrtC = sqrt(10005*one_squared, one_squared) return (Q*426880*sqrtC) // T # The last 5 digits or pi for various numbers of digits check_digits = { 100 : 70679, 1000 : 1989, 10000 : 75678, 100000 : 24646, 1000000 : 58151, 10000000 : 55897, } if __name__ == "__main__": digits = 100 pi = pi_chudnovsky_bs(digits) #raise SystemExit for log10_digits in range(1,11): digits = 10**log10_digits start =time() pi = pi_chudnovsky_bs(digits) pi = str(pi) pi = pi[:(len(str(pi)) // 2) + 1] length = int(len(str(pi))) - 1 print("Chudnovsky Binary Splitting Using GMPY: Digits",f"{digits:,}","\n--------------",time()-start,"--------------") print("Length Of " + f"{length:,}" + " Digits") It's my first answer, so I hope it helps!
Multiprocessing a function from main forking main as well in python
I am trying to do multiprocessing of a function 5 times by using python multiprocessing.Process library To my surprise I am also getting the prints that I have added 5 times more..my intuition is that main is also getting called 5 times. I added prints in the train function that I need to process 5 times I can see multiprocessing happening from the prints.But I am unable to figure it out why main is also getting called 5 times. Here is my code..Can someone please help a check what's wrong with this code. def train(rank,params, shared_model, optimizer,ticker): try: print("rank:",str(rank)," ",str(ticker),"\n") f.write("rank:"+str(rank)+" "+str(ticker)+"\n") data= pd.read_csv(ticker + '.csv') data = data.dropna() count = 0 max_timesteps = int(data.shape[0]*0.8) data = torch.DoubleTensor(np.asarray(data)) env = ENV(state_dim, action_dim, data) # init training variables state = env.reset() done = True episode_length = 0 count = 0 while count<max_timesteps-1: episode_length += 1 if done: cx = Variable(torch.zeros(1, state_dim)) hx = Variable(torch.zeros(1, state_dim)) else: cx = Variable(cx.data) hx = Variable(hx.data) values = [] log_probs = [] rewards = [] entropies = [] for step in range(max_timesteps): value, action_values, (hx, cx) = model((Variable(state.unsqueeze(0)), (hx, cx))) prob = F.softmax(action_values,dim = 0) log_prob = F.log_softmax(action_values,dim = 0) entropy = -(log_prob * prob).sum(1) entropies.append(entropy) action = prob.multinomial(num_samples=1).data log_prob = log_prob.gather(1, Variable(action)) values.append(value) log_probs.append(log_prob) state, reward, done = env.step(action.numpy()) print(ticker," reward", reward , " rank:",rank) count+=1 done = (done or count == max_timesteps-2) reward = max(min(reward, 1), -1) if done: episode_length = 0 state = env.reset() rewards.append(reward) if done: break R = torch.zeros(1, 1) if not done: value, _, _ = model((Variable(state.unsqueeze(0)), (hx, cx))) R = value.data values.append(Variable(R)) policy_loss = 0 value_loss = 0 R = Variable(R) gae = torch.zeros(1, 1) for i in reversed(range(len(rewards))): R = params.gamma * R + rewards[i] advantage = R - values[i] value_loss = value_loss + 0.5 * advantage.pow(2) TD = rewards[i] + params.gamma * values[i + 1].data - values[i].data gae = gae * params.gamma * params.tau + TD policy_loss = policy_loss - log_probs[i] * Variable(gae) - 0.01 * entropies[i] optimizer.zero_grad() (policy_loss + 0.5 * value_loss).backward() torch.nn.utils.clip_grad_norm_(model.parameters(), 40) optimizer.step() f.flush() except: print(ticker) traceback.print_exc() var = traceback.format_exc() f.write(str(ticker)+"\n") f.write("exception:\n"+str(var)) f.flush() # Implementing the Adam optimizer with shared states class Params(): def __init__(self): self.lr = 0.001 self.gamma = 0.99 self.tau = 1. self.seed = 1 self.num_processes = 5 self.num_steps = 20 self.max_episode_length = 10000 self.env_name = 'Breakout-v0' params = Params() state_dim = 6 action_dim = 3 model = ActorCritic(state_dim, action_dim) model.share_memory() optimizer = SharedAdam(model.parameters(), lr=params.lr) optimizer.share_memory() # set the parameters epochs = 1 state_dim = 6 action_dim = 3 max_action = 1 idx = 0 file_name = "%s" % ("computational__reward") directory="./pytorch_models" # instantiate policy tickers = pd.read_csv("tickers.csv") indices = tickers['Symbol'] jobs = [] #indices = ['FTK'] for ep in range(1): print("epoch:",ep) f.write("epoch:"+str(ep)+"\n") for ticker in indices: try: for rank in range(0, params.num_processes): # making a loop to run all the other processes that will be trained by updating the shared model if __name__ == '__main__': p = multiprocessing.Process(target=train, args=(rank, params, model, optimizer,ticker,)) jobs.append(p) p.start() for p in jobs: # creating a pointer that will allow to kill all the threads when at least one of the threads, or main.py will be killed, allowing to stop the program safely p.join() model.save("A3C_multi"+ str(ep)+"_" + file_name, directory="./pytorch_models") f.flush() except Exception as e: print(e) traceback.print_exc() var = traceback.format_exc() f.write(str(ticker)+"\n") f.write("exception:\n"+str(var)) model.save("A3C"+ str(ep)+"_" + file_name, directory="./pytorch_models") I am getting this print 6 times: epoch: 0 epoch: 0 epoch: 0 epoch: 0 epoch: 0 epoch: 0
Short answer Since you are running this on windows, all code that is not function or class definitions should be inside the if __name__ is "__main__" block. Long answer On POSIX operating systems, the multiprocessing module is implemented using the fork() system call, which creates a copy of a process. This is very handy because the second process is completely initialized out of the box. Microsoft windows does not have this system call. So Python tries to mimick this by starting a new Python interpreter and importing your program as a module. For this to work well importing your program should not have side effects. The best way to achieve that is to put anything that is not a class or function definition inside the if __name__ is "__main__" block. Since part of your code is outside the main block, it will be executed when your program is imported in the newly created Python processes. That is why you are seeing the multiple "epoch" prints.
Print does not fit the data interval settings
I am using this answer here and I have this code which get the gauge strain signal (2 channels) and then I apply a calibration step, then I print the 2 channels and the current time. But it looks like the print does not match the frequency I use in my code. from time import sleep from Phidget22.Phidget import * from Phidget22.Devices.VoltageRatioInput import * import time import datetime TIME_OUT = 5000 #5s beofre it throws a timeout exception DATA_INTERVAL = 50 #50ms sample frequency A0 = -6.128983223994E-06 B0 = -0.000059639277340 A1 = -6.101017778744E-06 B1 = -0.000286467338645 def onVoltageRatioChange0(self, voltageRatio): Masse = (voltageRatio - (B0) ) / (A0) self.masse = Masse def onVoltageRatioChange1(self, voltageRatio): Masse = (voltageRatio - (B1) ) / (A1) self.masse = Masse def results(): voltageRatioInput0 = VoltageRatioInput() voltageRatioInput0.masse = 0 voltageRatioInput0.setChannel(0) voltageRatioInput0.setOnVoltageRatioChangeHandler(onVoltageRatioChange0) voltageRatioInput0.openWaitForAttachment(TIME_OUT) voltageRatioInput0.setBridgeGain(BridgeGain.BRIDGE_GAIN_128) voltageRatioInput0.setDataInterval(DATA_INTERVAL) voltageRatioInput1 = VoltageRatioInput() voltageRatioInput1.masse = 0 voltageRatioInput1.setChannel(1) voltageRatioInput1.setOnVoltageRatioChangeHandler(onVoltageRatioChange1) voltageRatioInput1.openWaitForAttachment(TIME_OUT) voltageRatioInput1.setBridgeGain(BridgeGain.BRIDGE_GAIN_128) voltageRatioInput1.setDataInterval(DATA_INTERVAL) print(str(datetime.datetime.now()) + " / " + str(voltageRatioInput0.masse) + " / " + str(voltageRatioInput1.masse)) voltageRatioInput0.close() voltageRatioInput1.close() if __name__ == '__main__': try: while True: results() except KeyboardInterrupt: print("Goodbye") pass So normally using the voltageRatioInput0.setDataInterval(DATA_INTERVAL) it should print the value with a frequency of 20 hz. But it prints me this : 2019-11-22 10:24:59.460503 / -0.03847266852956798 / 0.2918630004986786 2019-11-22 10:25:00.099831 / -0.03695316689942101 / -0.02070779820379342 2019-11-22 10:25:00.772398 / -0.04029613574942367 / 0.28775155534154484 2019-11-22 10:25:01.420283 / -0.043487203384171676 / 0.25676361089420047 So clearly here I do not have 20 Hz...
A lot of time is probably spent in your result() function. I cannot reproduce here, but a simple python -m cProfile -s tottime your_program.py should help you to see where most of the time is spent each loop iteration. I guess that instanciation of a VoltageRatioInput() and VoltageRatioInput.close() are a good way to start. Could you try taking them outside the loop as in: from Phidget22.Phidget import * from Phidget22.Devices.VoltageRatioInput import * import datetime TIME_OUT = 5000 #5s beofre it throws a timeout exception DATA_INTERVAL = 50 #50ms sample frequency A0 = -6.128983223994E-06 B0 = -0.000059639277340 A1 = -6.101017778744E-06 B1 = -0.000286467338645 def onVoltageRatioChange0(self, voltageRatio): Masse = (voltageRatio - (B0) ) / (A0) self.masse = Masse def onVoltageRatioChange1(self, voltageRatio): Masse = (voltageRatio - (B1) ) / (A1) self.masse = Masse def results(voltageRatioInput0, voltageRatioInput1): voltageRatioInput0.masse = 0 voltageRatioInput0.setChannel(0) voltageRatioInput0.setOnVoltageRatioChangeHandler(onVoltageRatioChange0) voltageRatioInput0.openWaitForAttachment(TIME_OUT) voltageRatioInput0.setBridgeGain(BridgeGain.BRIDGE_GAIN_128) voltageRatioInput0.setDataInterval(DATA_INTERVAL) voltageRatioInput1.masse = 0 voltageRatioInput1.setChannel(1) voltageRatioInput1.setOnVoltageRatioChangeHandler(onVoltageRatioChange1) voltageRatioInput1.openWaitForAttachment(TIME_OUT) voltageRatioInput1.setBridgeGain(BridgeGain.BRIDGE_GAIN_128) voltageRatioInput1.setDataInterval(DATA_INTERVAL) print(str(datetime.datetime.now()) + " / " + str(voltageRatioInput0.masse) + " / " + str(voltageRatioInput1.masse)) if __name__ == '__main__': try: voltageRatioInput0 = VoltageRatioInput() voltageRatioInput1 = VoltageRatioInput() while True: results(voltageRatioInput0, voltageRatioInput1) voltageRatioInput0.close() voltageRatioInput1.close() except KeyboardInterrupt: print("Goodbye")
How to let a multi-processing python application quit cleanly
When I run a python script that uses multiprocessing I find it hard to get it to stop cleanly when it receives Ctrl-C. Ctrl-C has to be pressed multiple times and all sorts of error messages appear on the screen. How can you make a python script that uses multiprocessing and quits cleanly when it receives a Ctrl-C ? Take this script for example import numpy as np, time from multiprocessing import Pool def countconvolve(N): np.random.seed() # ensure seed is random count = 0 iters = 1000000 # 1million l=12 k=12 l0=l+k-1 for n in range(N): t = np.random.choice(np.array([-1,1], dtype=np.int8), size=l0 * iters) v = np.random.choice(np.array([-1,1], dtype=np.int8), size = l * iters) for i in xrange(iters): if (not np.convolve(v[(l*i):(l*(i+1))], t[(l0*i):(l0*(i+1))], 'valid').any()): count += 1 return count if __name__ == '__main__': start = time.clock() num_processes = 8 N = 13 pool = Pool(processes=num_processes) res = pool.map(countconvolve, [N] * num_processes) print res, sum(res) print (time.clock() - start)
Jon's solution is probably better, but here it is using a signal handler. I tried it in a VBox VM which was extremely slow, but worked. I hope it will help. import numpy as np, time from multiprocessing import Pool import signal # define pool as global pool = None def term_signal_handler(signum, frame): global pool print 'CTRL-C pressed' try: pool.close() pool.join() except AttributeError: print 'Pool has been already closed' def countconvolve(N): np.random.seed() # ensure seed is random count = 0 iters = 1000000 # 1million l=12 k=12 l0=l+k-1 for n in range(N): t = np.random.choice(np.array([-1,1], dtype=np.int8), size=l0 * iters) v = np.random.choice(np.array([-1,1], dtype=np.int8), size = l * iters) for i in xrange(iters): if (not np.convolve(v[(l*i):(l*(i+1))],t[(l0*i):(l0*(i+1))], 'valid').any()): count += 1 return count if __name__ == '__main__': # Register the signal handler signal.signal(signal.SIGINT, term_signal_handler) start = time.clock() num_processes = 8 N = 13 pool = Pool(processes=num_processes) res = pool.map(countconvolve, [N] * num_processes) print res, sum(res) print (time.clock() - start)
I believe the try-catch mentioned in a similar post here on SO could be adapted to cover it. If you wrap the pool.map call in the try-catch and then call terminate and join I think that would do it. [Edit] Some experimentation suggests something along these lines works well: from multiprocessing import Pool import random import time def countconvolve(N): try: sleepTime = random.randint(0,5) time.sleep(sleepTime) count = sleepTime except KeyboardInterrupt as e: pass return count if __name__ == '__main__': random.seed(0) start = time.clock() num_processes = 8 N = 13 pool = Pool(processes=num_processes) try: res = pool.map(countconvolve, [N] * num_processes) print res, sum(res) print (time.clock() - start) except KeyboardInterrupt as e: print 'Stopping..' I simplified your example somewhat to avoid having to load numpy on my machine to test but the critical part is the two try-except calls which handle the CTRL+C key presses.