qt gui 세마포어, 뮤텍스.

ninani12의 이미지

선배님들,
안녕하세요.

하루 하루 삽질에 허덕이고 있는 초보 개발자 입니다..

다름이 아니라 큐에 4개의 url이 있을경우 스레드를 생성을 해서 3초에 한번씩 리퀘스트를 주도록 구현을 할려고 합니다.
멀티스레드 특성상 동기화를 걸어놓지 않으면 우선순위에 의해서 임의로 접근을 한다는 구글링 검색을 통해

뮤텍스 또는 세마포어를 이용을 하여 하나의 스레드가 진입을 하면 나머지 스레드는 대기를 하도록 구현을 할려고 의도 했으나..
코드로는 구현이 되질 않아 제가 놓친부분이 있는지 궁금합니다.

추가적인 설명을 하자면
1. 스레드가 4개 생성이 됩니다.
2. 각 스레드마다 url을 리퀘스트 하는 getUrl 함수로 진입을 합니다.
3. 스레드1이 3초동안 대기하고 리퀘스트 날리고 업데이트, 스레드2가 그 다음에 대기하고 리퀘스트 날리고 업데이트.. 이렇게 3초동안 리퀘스트 날리고 업데이트를 진행을 하고 싶습니다.

하지만 아래 소스 보시면 아시겠지만..
스레드 4개가 서로 3초까지 돈 다음에 한꺼번에 리퀘스트를 날리고 업데이트를 받아고 있습니다.

추가적으로 stop버튼을 눌렀을 경우 어떤식으로 thread를 kill을 해야 할지 감이 잡히질 않습니다.
많은 조언 부탁 드립니다.

from PySide import QtCore, QtGui
from UI_mainwindow import Ui_MainWindow
from queue import Queue
import time, sys
import sys, re, urllib.request
 
class DownloadThread(QtCore.QThread):
    data_downloaded = QtCore.Signal(object)
    def __init__(self, urlq, i):
        QtCore.QThread.__init__(self)
        self.urlq = urlq
        self.id = i
        self.mutex = QtCore.QMutex()
 
    def getUrl(self, url, id):
        self.mutex.lock()
        sleepStep = 0.1
        delay = 0
        while delay < 3:
            time.sleep(sleepStep) # delay is actually set by while, but this holds for 'sleepStep' seconds
            delay += sleepStep
            print ("thread id - %s , delay - %s" %(id, delay))
 
        print ("thread id - %s , currnet url - %s" %(id, url))
        info = urllib.request.urlopen(url).info()
        self.data_downloaded.emit('%s' % (info))
        self.mutex.unlock()
        #info = urllib.request.urlopen(self.url).info()
        #print ("info - %s" %info)
        #self.list_widget.addItem('%s\n%s' % (self.url, info))
 
    def stop(self):
        print ("test - %s")
 
    def run(self):
        while not self.urlq.empty():
            self.url = self.urlq.get()
            time.sleep(3)
            htmlSource = self.getUrl(self.url, self.id)
            self.urlq.task_done()
 
        self.urlq.join()
 
class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
 
 
        self.connect(self.ui.actionStart, QtCore.SIGNAL('triggered()'),self.start)
 
    def start(self):
        self.urlq = Queue()
        urls = ['http://google.com', 'http://twitter.com', 'http://yandex.ru',
                'http://stackoverflow.com/', 'http://www.youtube.com/']
        for url in urls :
            self.urlq.put(url)
 
        self.threads = []
        for i in range(10):
            downloader = DownloadThread(self.urlq, i)
            downloader.data_downloaded.connect(self.on_data_ready)
            self.threads.append(downloader)
            downloader.start()
 
    def on_data_ready(self, data):
        print ("d - %s" %data)
 
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

tomahawk28의 이미지

>뮤텍스 또는 세마포어를 이용을 하여 하나의 스레드가 진입을 하면 나머지 스레드는 대기를 하도록 구현을 할려고 의도 했으나..
>코드로는 구현이 되질 않아 제가 놓친부분이 있는지 궁금합니다.

코드로 구현이 되질 않는다구요?

아래 사이트를 보시면 threading package를 사용해서 wait, notify 메소드로 자원을 제어 할 수 있습니다

https://docs.python.org/2/library/threading.html#condition-objects

또, 위 코드에 클래스 __init__ 부분에

> self.mutex = QtCore.QMutex()

이러면 뮤텍스를 인스턴스끼리 공유하는게 아니라 각 인스턴스마다 하나의 뮤텍스를 가지는 것 같은데, 아닌가요?

ninani12의 이미지

답변 달아주셔서 감사합니다.

말씀하신 내용을 곰곰히 생각해보니 비효율적인 프로그램이 될 수 있을 것 같습니다.
그러면 스레드가 생성이 되지만 이 스레드가 같이 인스턴스로 공유를 하면서 효율적으로 작동이 되기 위해서
알려주신 wait, notify로 제어를 하는 방식으로 변경해보겠습니다.

감사합니다.

emptynote의 이미지

쓰레드는 병렬성을 극대화 하기 위해서 사용하는겁니다.

쓰레드 도입 목적은 "스레드 4개가 서로 3초까지 돈 다음에 한꺼번에 리퀘스트를 날리고 업데이트를 받아고 있습니다." 를 위해서 입니다.

ninani12의 이미지

소중한 답변 감사 드립니다.

그러면 추가적인 질문이 있습니다.
아직 기초가 부족하여 질문이 두서 없을 수도 있다는점 양해 부탁 드립니다.

사실 해당 소스는 웹 크롤링을 공부를 하기위해 제작중인 소스 입니다.
지금은 서로 각자 다른 url을 큐에 넣고 리퀘스트를 날리고 있지만 제가 염려가 되는 하나의 도메인으로부터 시작해서 하위도메인까지 모두 큐에 넣고 한꺼번에 돌릴경우 서버에 무리가 갈까봐 걱정입니다.

예를 들어서 대표 페이지 크롤링을해서 큐에 20개가 들어갔고 스레드가 서로 다 돈다음에 한꺼번에 리퀘스트를 날리는게 반복되다 보면 서버에 무리가 갈까봐 걱정이 됩니다.

위의 내용처럼 구현을 하기 위해서 저는 그냥 각 스레드별로 딜레이를 줘서 요청을 할 생각이었는데요.

혹시 제가 잘못 설계를 하고 있다면 조언좀 부탁 드립니다.

ninani12의 이미지

답변 달아주셔서 감사합니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.