简体   繁体   中英

Child thread doesn`t really spawn or has some issue in python?

I am trying to get rows for a particular machine name from v$session and spawning a child thread which calls a function called kill_it() to work on its particular row. And the main do_this() sleeps for 100sec and checks for newer rows.

def do_this():

    sql='select * from v$session where machine like abc'
    session=Popen(['sqlplus','-S','/ as sysdba'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
    session.stdin.write(sql)
    stdout,stderr=session.communicate()
    stdout=stdout.strip()
    stdout=stdout.split('\n')

    for i in range (len(stdout)):

        if 'no rows selected' not in stdout:
            sql_output=stdout[i].split(',')
            client_info=sql_output[0]
            sid=sql_output[1]
            serial=sql_output[2]
            program=sql_output[3]
            last_call=sql_output[4]
            process=sql_output[5]
            machine=sql_output[6]

            t = Thread(target=kill_it, args=(client_info,sid,serial,program,last_call,process,machine,))
            print t
            t.start()



while True:
    do_this()
    time.sleep(100)

But in the kill_it() function which should run in its own thread, but when I am trying to put the child thread to sleep for 10secs, it is instead sleeping for 100secs or even if I remove the sleep it doesnt really keep looking for xyz in client info.

def kill_it(client_info,sid,serial,program,last_call,process,machine):

    while True:
        print "thread is :"+str(current_thread())
        last_call=int(last_call)
        if 'xyz' in client_info and last_call>100 :
            command='alter system kill session \''+sid+','+serial+'\' immediate;'
            print command
            '''
            session=Popen(['sqlplus','-S','/ as sysdba'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
            session.stdin.write(command)
            stdout,stderr=session.communicate()
            print stdout
            print stderr
            '''

            print 'done'
            break;

        else:
            print 'Sleeping coz job didn`t run for more than 5mins'
            time.sleep(10)

WOrks as expected when there is one row but for more than one gives issues.

Firstly:

In regards to your comments, you MUST ALWAYS join threads and processes that you spawn to ensure everything is cleaned up. If that interrupts your program's flow in an intrusive way, then you need to redesign your program because something is wrong. You should take a closer look at the Python multiprocessing library, in particular, look at multiprocessing.Pool() .

Secondly:

Take a close look at your do_this() function:

# stuff...
stdout=stdout.strip()
stdout=stdout.split('\n')

You can daisy-chain string operations:

# stuff..
stdout=stdout.strip().split('\n')

Now on to your loop. I don't think it's doing what you really intended, and has several things in it you can improve:

# the variable 'stdout' is now a tuple as returned by string.split('\n'), right?

# if you need a loop index, use enumerate() instead of this
for i in range (len(stdout)):

    # this if statement checks for membership in the tuple 'stdout' which is 
    # going to have the same result every time - did you mean to check the
    # elements of the tuple you're iterating over for something instead?
    if 'no rows selected' not in stdout: 

        # indexing into an iterable with a loop index is usually wrong in python 
        # not always, but usually
        sql_output=stdout[i].split(',') 

        # do you need to split this thing up into so many components when they're
        # all getting passed anyway?
        client_info=sql_output[0] 
        sid=sql_output[1]
        serial=sql_output[2]
        program=sql_output[3]
        last_call=sql_output[4]
        process=sql_output[5]
        machine=sql_output[6]

        t = Thread(target=kill_it, args=(client_info,sid,serial,program,last_call,process,machine,))
        print t
        t.start()
        # threads and processes should ALWAYS be joined

I would suggest refactoring your do_this() code to something like this:

def do_this():

    sql='select * from v$session where machine like abc'
    session=Popen(['sqlplus','-S','/ as sysdba'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
    session.stdin.write(sql)
    stdout,stderr=session.communicate()
    stdout=stdout.strip().split('\n')

    if 'no rows selected' not in stdout:
        pool = multiprocessing.Pool()
        pool.map(kill_it, stdout) # blocking call until all are done
        pool.close()
        pool.join()

    return

pool.map() calls the function kill_it on every object in the iterable passed to it, which in this case is the tuple that resulted from splitting stdout. If you choose to do this, it will be up to you to move the job of splitting the line on the commas into the kill_it function and replace the long argument list with a single argument: the string to be split.

TL;DR

I see two issues that could be causing you problems:
1. ALWAYS join your threads and processes. You can get odd behavior if you don't.
2. Check your if statement in the for loop of do_this() . I don't think you really meant to check the entire stdout tuple for 'no rows selected' there, because it is going to be the same result every time, so it should be in a loop. You may be killing/not killing rows you did/did not intend to.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM