2009-08-11 10 views
10

Java'da, olayları dinleyecek ve daha sonra bunları Jython'da işleyecek bir çerçeve yapıyorum. Farklı senaryolara farklı etkinlik türleri gönderilecektir. jython PythonInterpreter.exec() çağrıldığında komut dosyası derlemek için oldukça uzun bir süre gerektiğindenJava'dan çok satırlı jython komut dosyaları nasıl çalışır?

, ben komut önceden derlemek zorunda kalacaktır. Ben o şu şekilde yapıyorum:

olayları Şimdi benim bilmece için
PythonInterpreter pi = new PythonInterpreter(); 
pi.set("variable_1", "value_1"); 
pi.set("variable_x", "value_x"); 
pi.exec(compiled); 

geldikçe PyCode derlenmiş nesne havuzuna itti ve kullanılacak

// initialize the script as string (would load it from file in final version) 
String script = "print 'foo'"; 
// get the compiled code object 
PyCode compiled = org.python.core.__builtin__.compile(script, "<>", "exec"); 
- birden çok olduğunu gerçekleşebilir Aynı anda gerçekleşen belirli türdeki olaylar - böylece, aynı anda çalışan çok sayıda betik örneği.

Hemen hemen tüm komut muhtemelen kısa ömürlü kalacağını - 100 hatları, hiçbir döngüler kadar. Sayı ve sıklık tamamen rastgele (kullanıcı tarafından oluşturulan olaylar) ve olay türü başına saniyede 0'dan 200'e kadar olabilir.

Bunu yapmanın en iyi yolu ne olurdu? Birkaç alternatif bakıyorum: tetikleyici olay noktada

  1. kullanım senkronizasyonu - Bu aynı komut birden çok örneğini önleyeceğini hem de olaylar bunlar
  2. havuzu oluşturmak olmalıdır olduğunca çabuk işleme tabi tutulmaz bir şekilde orijinal PyCode nesne klonlama tarafından doldurulan aynı tip komut - lag kaldırılır bu şekilde - en büyük problem, muhtemelen exec() bitirdiğinde havuz
  3. dinamik gerektiğinde ebeveynden komut nesnesi klonlamak ve sonra atın boyutları optimize olacaktır derlemeden ancak hala klonlama yönteminde mevcut olan

Muhtemelen 2 ve 3 numaralı sayıların kombinasyonu en iyi dinamik havuz boyutları olabilir mi?

Peki, herhangi bir düşünce? ;)

cevap

3

O PyCode örnekleri (sınıflar kamu üyelerin bir sürü vardır) değişmez olmadıklarını üzücü.

PyRunnable r = constructor.newInstance(name); 
PyCode pc = r.getMain(); 

olacağım: Eğer gerektiğinde her Ardından komut dosyası için PyCode örneklerini üretmek için kurucu kullanabilirsiniz

// TODO: generate this name 
final String name = "X"; 
byte[] scriptBytes = PyString.to_bytes(script); 
CompilerFlags flags = Py.getCompilerFlags(); 
ByteArrayOutputStream ostream = new ByteArrayOutputStream(); 
Module.compile(parser.parse(new ByteArrayInputStream(scriptBytes), "exec", 
    "<>", flags), ostream, name, "<>", false, false, false, flags); 
byte[] buffer = ostream.toByteArray(); 
Class<PyRunnable> clazz = BytecodeLoader.makeClass(name, null, buffer); 
final Constructor<PyRunnable> constructor = clazz 
    .getConstructor(new Class[] { String.class }); 

:

Bu kodu kullanarak yeniden kullanılabilir bir komut dosyası derleme olabilir İlk olarak bunun bir şey yapmanın iyi bir yolu olmadığını itiraf etmek ve muhtemelen Jython'la olan deneyimsizliğim hakkında hacimler dile getirmek. Bununla birlikte, her seferinde derlenmekten çok daha hızlıdır. Kod Jython 2.2.1 altında çalışır, ancak Jython 2.5 altında derlenmez (sizinki de olmayacaktır).

+0

Güzel! Bir çekicilik gibi çalışır;) İlk Module.compile (...) çağrılmadan önce bir PythonInterpreter örneğinin oluşturulmasının ZORUNLUDUR. Değilse, NullPointerException SyspathJavaLoader'dan atılır.loadClass() En çok yardımcı oldunuz. Şimdi tek yapmam gereken bunu dinamik olarak yeniden boyutlandırılabilir bir betik havuzuna entegre etmektir ... – nEJC

+0

Jython 2.5 için herhangi bir eşdeğer var mı? – Laurent

+0

@Laurent - Hayır, bu alana baktığımdan beri bu alana bakmadım – McDowell

1

PythonInterpreter pahalıdır, bu kod yalnızca bir tane kullanacaktır.

#action.py 
def execute(filename, action_locals): 
    #add caching of compiled scripts here 
    exec(compile(open(filename).read(), filename, 'exec'), action_locals) 

//class variable, only one interpreter 
PythonInterpreter pi; 

//run once in init() or constructor 
pi = new PythonInterpreter();//could do more initialization here 
pi.exec("import action"); 

//every script execution 
PyObject pyActionRunner = pi.eval("action.execute"); 
PyString pyActionName = new PyString(script_path); 
PyDictionary pyActionLocals = new PyDictionary(); 
pyActionLocals.put("variable_1", "value_1"); 
pyActionLocals.put("variable_x", "value_x") 
pyActionRunner.__call__(pyActionName, pyActionLocals); 

#example_script.py 
print variable_1, variable_x 
+0

İlginç, fakat bildiğim kadarıyla PythonInterpreter iplik güvenli değil, bu yüzden muhtemelen iyi bir fikir değil (en azından benim için) .. bazı test yapmak zorunda kalacak olsa da ... – nEJC

+0

Evet, PythonInterpreter iş parçacığı güvenli değil, tam olarak neden bu şekilde yaptım nedeni. pi.eval ("action.execute"), yalnızca java nesnesi olarak yöntemin bir örneğini verir, çalıştırmaz. – Ron