2012-06-08 21 views
10

Bir PostgreSQL veritabanını sorgulaması gereken bir Django web uygulamasında çalışıyorum. Python threading arabirimini kullanarak eşzamanlılık uygularken, sorgulanan öğeler için DoesNotExist hataları alıyorum. Tabii ki, bu hatalar sıralı olarak sorguları gerçekleştirirken gerçekleşmez. Gördüğünüz gibiThreading kullanırken Django içindeki veritabanı hataları

class ThreadingTest(TestCase): 
    fixtures = ['demo_city',] 

    def test_sequential_requests(self): 
     """ 
     A very simple request to database, made sequentially. 

     A fixture for the cities has been loaded above. It is supposed to be 
     six cities in the testing database now. We will made a request for 
     each one of the cities sequentially. 
     """ 
     for number in range(1, 7): 
      c = City.objects.get(pk=number) 
      self.assertEqual(c.pk, number) 

    def test_threaded_requests(self): 
     """ 
     Now, to test the threaded behavior, we will spawn a thread for 
     retrieving each city from the database. 
     """ 

     threads = [] 
     cities = [] 

     def do_requests(number): 
      cities.append(City.objects.get(pk=number)) 

     [threads.append(threading.Thread(target=do_requests, args=(n,))) for n in range(1, 7)] 

     [t.start() for t in threads] 
     [t.join() for t in threads] 

     self.assertNotEqual(cities, []) 

, ilk test gerçekten hiçbir sorunla çalışıyoruz sırayla bazı veritabanı isteklerini gerçekleştirir:

beni beklenmedik bir davranış sergilemeye yazdığı bir birim testi gösterelim. Bununla birlikte, ikinci test tam olarak aynı istekleri yerine getirir, ancak her talep bir iş parçacığında ortaya çıkar. Bu aslında başarısız oluyor ve DoesNotExist istisnası döndürüyor.

Exception in thread Thread-6: 
Traceback (most recent call last): 
    File "/usr/lib/python2.6/threading.py", line 532, in __bootstrap_inner 
    self.run() 
    File "/usr/lib/python2.6/threading.py", line 484, in run 
    self.__target(*self.__args, **self.__kwargs) 
    File "/home/jose/Work/cesta/trunk/src/cesta/core/tests/threadbase.py", line 45, in do_requests 
    cities.append(City.objects.get(pk=number)) 
    File "/home/jose/Work/cesta/trunk/parts/django/django/db/models/manager.py", line 132, in get 
    return self.get_query_set().get(*args, **kwargs) 
    File "/home/jose/Work/cesta/trunk/parts/django/django/db/models/query.py", line 349, in get 
    % self.model._meta.object_name) 
DoesNotExist: City matching query does not exist. 


FAIL 

====================================================================== 
FAIL: test_threaded_requests (cesta.core.tests.threadbase.ThreadingTest) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "/home/jose/Work/cesta/trunk/src/cesta/core/tests/threadbase.py", line 52, in test_threaded_requests 
    self.assertNotEqual(cities, []) 
AssertionError: [] == [] 

---------------------------------------------------------------------- 
Ran 2 tests in 0.278s 

FAILED (failures=1) 
Destroying test database for alias 'default' ('test_cesta')... 

tüm bu olduğunu unutmayın ...

test_sequential_requests (cesta.core.tests.threadbase.ThreadingTest) ... ok 
test_threaded_requests (cesta.core.tests.threadbase.ThreadingTest) ... 

Exception in thread Thread-1: 
Traceback (most recent call last): 
    File "/usr/lib/python2.6/threading.py", line 532, in __bootstrap_inner 
    self.run() 
    File "/usr/lib/python2.6/threading.py", line 484, in run 
    self.__target(*self.__args, **self.__kwargs) 
    File "/home/jose/Work/cesta/trunk/src/cesta/core/tests/threadbase.py", line 45, in do_requests 
    cities.append(City.objects.get(pk=number)) 
    File "/home/jose/Work/cesta/trunk/parts/django/django/db/models/manager.py", line 132, in get 
    return self.get_query_set().get(*args, **kwargs) 
    File "/home/jose/Work/cesta/trunk/parts/django/django/db/models/query.py", line 349, in get 
    % self.model._meta.object_name) 
DoesNotExist: City matching query does not exist. 

... diğer konu da benzer çıktı verir:

bu birim testlerinin icra çıktı böyledir SQLite veya benzerleriyle değil, iş parçacığı güvenli olması beklenen bir PostgreSQL veritabanında oluyor. Test ayrıca PostgreSQL kullanılarak çalıştırıldı. Bu noktada, neyin başarısız olabileceği konusunda tamamen kayboldum. Herhangi bir fikir veya öneri?

Teşekkürler!

DÜZENLEME: Testlerden çıkıp çıkmadığını kontrol etmek için küçük bir görünüm yazdım. İşte görünümün kodudur.

def get_cities(request): 
    queue = Queue.Queue() 

    def get_async_cities(q, n): 
     city = City.objects.get(pk=n) 
     q.put(city) 

    threads = [threading.Thread(target=get_async_cities, args=(queue, number)) for number in range(1, 5)] 

    [t.start() for t in threads] 
    [t.join() for t in threads] 

    cities = list() 

    while not queue.empty(): 
     cities.append(queue.get()) 

    return render_to_response('async/cities.html', {'cities': cities}, 
     context_instance=RequestContext(request)) 

(dikkate görünüm kodu içinde uygulama mantığını yazma çılgınlık almak bu kavramın sadece bir kanıtı olduğunu unutmayın ve yok asla olmaz Lütfen gerçek uygulama)

Sonuç, kodun güzel çalıştığı, isteklerin iş parçacığı içinde başarılı bir şekilde yapıldığı ve görünümün URL'lerini aradıktan sonra şehirleri gösterdiği sonucudur.

Yani, kodları sınamanız gerektiğinde, iş parçacığı kullanarak sorgu yapmak yalnızca sorun olacaktır. Üretimde, sorunsuz çalışacaktır.

Bu tür kodu başarılı bir şekilde sınamak için yararlı öneriler var mı?

+0

Fikstürün içe aktarıldığından emin misiniz? "Fikstür demo_city işlenen" ya da böyle bir şey ...... yapıştırabilir miyim? Ah, nevermind .. sadece tam soru okumadım .. – Tisho

cevap

2

Bu, işlemlerle ilgili bir sorun gibi görünüyor. Geçerli istekte (veya testte) elemanlar oluşturuyorsanız, neredeyse kesinlikle diğer iş parçacığındaki ayrı bağlantıdan erişilemeyen işlenmemiş bir işlemde bulunurlar. Bunu işe almak için muhtemelen manage your transctions manually'a ihtiyacınız vardır.

+0

Aslında sorgular herhangi bir veri değiştirmiyor, ama sadece veritabanından alınıyor. Yani, notunuzdaki notu alamıyorum. Her neyse, "do_requests" işlevindeki isteği işlenmemiş bir SQL sorgusuyla değiştirdim ve sonuçlar aynı. –

+0

https://docs.djangoproject.com/en/1.8/topics/db/transactions/ Yanıttaki bağlantı artık çalışmıyor çünkü v1.4 için. – Heliodor

10

TransactionTestCase kullanmayı deneyin:

class ThreadingTest(TransactionTestCase): 

dizge hafızasında verileri tutar ve bir veritabanına COMMIT sorunu yoktur. Muhtemelen iş parçacıkları, henüz orada işlem yapılmazken, doğrudan DB'ye bağlanmaya çalışıyor.Burada Seedescription: https://docs.djangoproject.com/en/dev/topics/testing/?from=olddocs#django.test.TransactionTestCase

TransactionTestCase ve dizge veritabanı bilinen bir duruma ve tamamlama ve geri alma etkisini test etmek test kodu yeteneğinin sıfırlanır hangi şekilde hariç özdeştir. Bir TransactionTestCase, sınama, tüm tabloları kesen ve ilk verileri yeniden yükleyerek tarafından çalıştırılmadan önce veritabanını sıfırlar. Bir TransactionTestCase, bu çağrıların geri çağrılmasını ve geri alınmasını arayabilir ve bu çağrıların etkilerini veritabanında gözlemleyebilir.

+0

bu gitmek için yaklaşıyor –

0

dolayısıyla değişiklikler diğer iş parçacığı tarafından görülmez, dokümantasyon Şimdi, işlem bir TestCase içine işlediği henüz

class LiveServerTestCase(TransactionTestCase): 
    """ 
    ... 
    Note that it inherits from TransactionTestCase instead of TestCase because 
    the threads do not share the same transactions (unless if using in-memory 
    sqlite) and each thread needs to commit all their transactions so that the 
    other thread can see the changes. 
    """ 

bu kısmından daha net hale gelir.

İlgili konular