คลังเก็บป้ายกำกับ: python

ใช้ python เรียกโปรแกรมอื่น โดยมี timeout

วันจันทร์ที่ผ่านมาผมนั่งเขียน grader อย่างบ้าคลั่ง เพราะต้องเอามาใช้ตรวจโปรแกรมน้องๆ ในวันอังคาร ผมเขียน grader ด้วยภาษา Python หลายๆคนคงทราบดีว่าโปรแกรม grader เป็นโปรแกรมที่ทำหน้าที่ compile และ run โปรแกรมอื่น เพื่อตรวจสอบว่า input ที่ใส่เข้าไปตรงกับ output ที่ถูกต้องหรือไม่ ถ้าถูกต้องทุก input ก็ถือว่าผ่าน

แต่ว่าโปรแกรมที่เอามาตรวจอาจรันแล้วเกิดอาการติดลูป หรือรันไม่รู้จบ เราจึงต้องกำหนด timeout ว่าให้รันได้ไม่เกินกี่วินาที ถ้าโปรแกรมรันนานเกินไป โปรแกรม grader จะต้องหยุดการทำงาน (End Process) ของโปรแกรมที่ถูกตรวจ

ปรากฏว่าผมไปค้นๆ ในเน็ตก็ไม่เจอตัวอย่างโปรแกรม python ที่สามารถ รันโปรแกรมอื่น แล้วกำหนด timeout แบบง่ายๆ เลย ผมก็เลยพยายามเขียนเอง 😀 ได้โค้ดมาดังนี้ (ใช้ thread และ subprocess)

import subprocess
from time import sleep
from threading import Thread

class process(Thread):
    # written by Natt Piyapramote 
    # requires: Python 2.6
    def __init__(self, filename, input_txt=None):
        Thread.__init__(self)
        self.filename = filename
        self.input_txt = input_txt
        self.status = 0
        self.output = ''
        
    def run(self):
        self.process = subprocess.Popen(self.filename,
                                   stdin=subprocess.PIPE, stdout=subprocess.PIPE)
        self.output, self.err = self.process.communicate(self.input_txt)
        self.status = 1

def run_process(filename, input_txt=None, timeout=1):
    "run a process with timeout"
    
    p = process(filename, input_txt)
    p.start()
    p.join(timeout)

    if p.status == 0:   # process still running?
        p.process.terminate()
        while p.isAlive():
            sleep(0.1)
            print 'killing process...'
    
    return p.output

ตัวอย่างการใช้งานฟังก์ชันนี้ก็

run_process('c:windowsnotepad.exe', timeout=4)

ฟังก์ชัน run_process จะไปเรียกโปรแกรม notepad.exe ให้ทำงาน (ซึ่ง notepad จะรันไปเรื่อยๆ ไม่ปิดตัวเอง) ดังนั้นฟังก์ชัน run_process จะหยุดการทำงานของ notepad ภายในเวลา 4 วินาที

นอกจากนี้ถ้าเรารันโปรแกรมที่เป็น Console Application เราสามารถกำหนด Input ให้กับ Standard Input (stdin) และอ่านค่าจาก Standard Output (stdout) ของโปรแกรมที่รันได้ด้วย (กำหนด Input ให้ตัวแปร input_txt แล้วฟังก์ชันจะคืนค่าข้อความจาก stdout)

อ้อ… ฟังก์ชันนี้ต้องใช้ Python 2.6 นะครับ

Advertisements

อ่านไฟล์ใน python อย่างรวดเร็วและมีประสิทธิภาพ

ก่อนหน้านี้นิสัยไม่ดี ชอบเขียนโปรแกรมอ่านไฟล์ประมาณนี้

lines = open('file.txt', 'r').read().split('n')
for line in lines:
    # do something

คำสั่ง read() แบบไม่กำหนด parameter จะอ่านไฟล์ทั้งหมดเข้ามาไว้ในหน่วยความจำ ถ้าไฟล์มีขนาดเล็ก ก็คงไม่มีปัญหาอะไร แต่เมื่อคืนเขียนโปรแกรมตัดคำไฟล์ใหญ่ประมาณ 64mb ปรากฏว่าโปรแกรมทำงานช้าลงมาก (จากไฟล์เล็กๆ ~7000 คำ/วินาที พอเจอไฟล์ใหญ่ๆเหลือ ~700 คำ/วินาที)

พออ่าน Python Doc แล้วเปลี่ยนวิธีเขียนโปรแกรมอ่านไฟล์เป็นแบบนี้แทน (ซึ่งมีประสิทธิภาพมากกว่า เพราะค่อยๆ อ่านทีละบรรทัด)

f = open('file.txt', 'r')
for line in f:
    # do something
f.close()

ปรากฏว่า ไฟล์จะใหญ่แค่ไหน โปรแกรมก็ทำงานที่ความเร็ว ~7000 คำ/วินาที 😀
ปล. มาเขียนบล็อกไว้เผื่อคนอื่นจะเจอปัญหาโง่ๆ แบบนี้ T_T (หรือไม่เค้าก็คงจะเขียนกันแบบล่างซะส่วนใหญ่ล่ะมั้ง)
ปล2. วิธีอ่านไฟล์แบบล่าง มีปัญหาคือ ถ้าโปรแกรมเราจำเป็นต้องกระโดดไปอ่านข้อความที่บรรทัดนู้นที บรรทัดนี้ทีก็คงจะทำไม่ได้ครับ

EDIT: ใช้ with (Context Manager ของ python) ช่วย handle การปิดไฟล์เวลาเกิด exception หรือปัญหาต่างๆ ได้ตามนี้ครับ:

with open('patties.txt', 'r') as patties:
    for line in patties:
        print line

วนลูป แล้วลบ “ของ” ออกจาก list

คุณเคยต้องเขียนโปรแกรมที่วนลูปบน list แล้วลบ “ของ (object)” ออกจาก list นั้นหรือไม่? ลองยกตัวอย่างโปรแกรมง่ายๆ สมมติให้ list A เก็บเลขจำนวนเต็ม แล้วคุณต้องการลบเลขที่หารสามลงตัว ออกจาก list A โค้ดของคุณก็อาจจะเป็น

Python C#
A = [1, 2, 3, 6, 7, 9, 12]
for x in A:
    if x % 3 == 0:
        A.remove(x)

List A = new List(new int[]{1, 2, 3, 6, 7, 9, 12});
foreach(int x in A)
{
    if(x % 3 == 0)
        A.Remove(x);
}

ในบล็อกนี้ขออนุญาตยกตัวอย่างแค่ 2 ภาษา คือ Python และ C# นะครับ สำหรับฝั่ง C# จะเจอกับ “Unhandled Exception: System.InvalidOperationException: Collection was modified;” (เขาบอกว่า เกิดการกระทำที่ไม่ถูกต้อง เนื่องจาก list ถูกแก้ไขระหว่างวนลูป) ส่วนคนใช้ Python จะไม่เจอปัญหาอะไรเวลารันครับ แต่พอลองพิมพ์ A ออกมาดูจะพบว่า

A = [1, 2, 6, 7, 12]

แงว… ทำไม 6 กับ 12 ยังโผล่ออกมา? ในเมื่อมันน่าจะ mod 3 ลงตัว… ในบล็อกนี้เราจะมาดูวิธีแก้ปัญหาที่มักจะเจอบ่อยๆ ปัญหานี้กันครับ

อ่านเพิ่มเติม วนลูป แล้วลบ “ของ” ออกจาก list

เรียงข้อมูลใน Python Dictionary ด้วย Value

เคยไหมที่เก็บข้อมูลใน Dictionary ใน python (เก็บเป็น key->value) แล้วต้องการเรียงข้อมูลตาม value

เช่น เก็บคะแนนดังนี้ (key คือ ชื่อคน, value คือ คะแนน)

scores = {'nattster':3.50, 'b4lmung':3.49, 'joe':4.00}

เราสามารถเรียงข้อมูลตาม value ได้อย่างง่ายดายด้วยคำสั่งต่อไปนี้

sorted_scores = sorted(scores.iteritems(), key=lambda (k,v): (v,k))

แต่! ผลลัพธ์ที่ได้จะเป็น list นะครับ โดยมีสมาชิกเป็น 2-tuple (ผลลัพธ์ที่ได้ตามนี้ครับ)

[('b4lmung', 3.4900000000000002), ('nattster', 3.5), ('joe', 4.0)]

แล้วถ้าต้องการเรียงจากมากไปน้อย ก็เรียกคำสั่ง

sorted_scores.reverse()